Add support for multiple line text and perfdata to nagios parser (#5601)
This commit is contained in:
parent
e793a69533
commit
60027cf902
|
@ -3,12 +3,12 @@ package exec
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kballard/go-shellquote"
|
"github.com/kballard/go-shellquote"
|
||||||
|
@ -61,39 +61,18 @@ func NewExec() *Exec {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Runner interface {
|
type Runner interface {
|
||||||
Run(*Exec, string, telegraf.Accumulator) ([]byte, error)
|
Run(string, time.Duration) ([]byte, []byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandRunner struct{}
|
type CommandRunner struct{}
|
||||||
|
|
||||||
func AddNagiosState(exitCode error, acc telegraf.Accumulator) error {
|
|
||||||
nagiosState := 0
|
|
||||||
if exitCode != nil {
|
|
||||||
exiterr, ok := exitCode.(*exec.ExitError)
|
|
||||||
if ok {
|
|
||||||
status, ok := exiterr.Sys().(syscall.WaitStatus)
|
|
||||||
if ok {
|
|
||||||
nagiosState = status.ExitStatus()
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("exec: unable to get nagios plugin exit code")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("exec: unable to get nagios plugin exit code")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fields := map[string]interface{}{"state": nagiosState}
|
|
||||||
acc.AddFields("nagios_state", fields, nil)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CommandRunner) Run(
|
func (c CommandRunner) Run(
|
||||||
e *Exec,
|
|
||||||
command string,
|
command string,
|
||||||
acc telegraf.Accumulator,
|
timeout time.Duration,
|
||||||
) ([]byte, error) {
|
) ([]byte, []byte, error) {
|
||||||
split_cmd, err := shellquote.Split(command)
|
split_cmd, err := shellquote.Split(command)
|
||||||
if err != nil || len(split_cmd) == 0 {
|
if err != nil || len(split_cmd) == 0 {
|
||||||
return nil, fmt.Errorf("exec: unable to parse command, %s", err)
|
return nil, nil, fmt.Errorf("exec: unable to parse command, %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command(split_cmd[0], split_cmd[1:]...)
|
cmd := exec.Command(split_cmd[0], split_cmd[1:]...)
|
||||||
|
@ -105,44 +84,35 @@ func (c CommandRunner) Run(
|
||||||
cmd.Stdout = &out
|
cmd.Stdout = &out
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
|
|
||||||
if err := internal.RunTimeout(cmd, e.Timeout.Duration); err != nil {
|
runErr := internal.RunTimeout(cmd, timeout)
|
||||||
switch e.parser.(type) {
|
|
||||||
case *nagios.NagiosParser:
|
|
||||||
AddNagiosState(err, acc)
|
|
||||||
default:
|
|
||||||
var errMessage = ""
|
|
||||||
if stderr.Len() > 0 {
|
|
||||||
stderr = removeCarriageReturns(stderr)
|
|
||||||
// Limit the number of bytes.
|
|
||||||
didTruncate := false
|
|
||||||
if stderr.Len() > MaxStderrBytes {
|
|
||||||
stderr.Truncate(MaxStderrBytes)
|
|
||||||
didTruncate = true
|
|
||||||
}
|
|
||||||
if i := bytes.IndexByte(stderr.Bytes(), '\n'); i > 0 {
|
|
||||||
// Only show truncation if the newline wasn't the last character.
|
|
||||||
if i < stderr.Len()-1 {
|
|
||||||
didTruncate = true
|
|
||||||
}
|
|
||||||
stderr.Truncate(i)
|
|
||||||
}
|
|
||||||
if didTruncate {
|
|
||||||
stderr.WriteString("...")
|
|
||||||
}
|
|
||||||
|
|
||||||
errMessage = fmt.Sprintf(": %s", stderr.String())
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("exec: %s for command '%s'%s", err, command, errMessage)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch e.parser.(type) {
|
|
||||||
case *nagios.NagiosParser:
|
|
||||||
AddNagiosState(nil, acc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out = removeCarriageReturns(out)
|
out = removeCarriageReturns(out)
|
||||||
return out.Bytes(), nil
|
if stderr.Len() > 0 {
|
||||||
|
stderr = removeCarriageReturns(stderr)
|
||||||
|
stderr = truncate(stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.Bytes(), stderr.Bytes(), runErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func truncate(buf bytes.Buffer) bytes.Buffer {
|
||||||
|
// Limit the number of bytes.
|
||||||
|
didTruncate := false
|
||||||
|
if buf.Len() > MaxStderrBytes {
|
||||||
|
buf.Truncate(MaxStderrBytes)
|
||||||
|
didTruncate = true
|
||||||
|
}
|
||||||
|
if i := bytes.IndexByte(buf.Bytes(), '\n'); i > 0 {
|
||||||
|
// Only show truncation if the newline wasn't the last character.
|
||||||
|
if i < buf.Len()-1 {
|
||||||
|
didTruncate = true
|
||||||
|
}
|
||||||
|
buf.Truncate(i)
|
||||||
|
}
|
||||||
|
if didTruncate {
|
||||||
|
buf.WriteString("...")
|
||||||
|
}
|
||||||
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeCarriageReturns removes all carriage returns from the input if the
|
// removeCarriageReturns removes all carriage returns from the input if the
|
||||||
|
@ -173,9 +143,11 @@ func removeCarriageReturns(b bytes.Buffer) bytes.Buffer {
|
||||||
|
|
||||||
func (e *Exec) ProcessCommand(command string, acc telegraf.Accumulator, wg *sync.WaitGroup) {
|
func (e *Exec) ProcessCommand(command string, acc telegraf.Accumulator, wg *sync.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
_, isNagios := e.parser.(*nagios.NagiosParser)
|
||||||
|
|
||||||
out, err := e.runner.Run(e, command, acc)
|
out, errbuf, runErr := e.runner.Run(command, e.Timeout.Duration)
|
||||||
if err != nil {
|
if !isNagios && runErr != nil {
|
||||||
|
err := fmt.Errorf("exec: %s for command '%s': %s", runErr, command, string(errbuf))
|
||||||
acc.AddError(err)
|
acc.AddError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -183,10 +155,18 @@ func (e *Exec) ProcessCommand(command string, acc telegraf.Accumulator, wg *sync
|
||||||
metrics, err := e.parser.Parse(out)
|
metrics, err := e.parser.Parse(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
acc.AddError(err)
|
acc.AddError(err)
|
||||||
} else {
|
return
|
||||||
for _, metric := range metrics {
|
|
||||||
acc.AddFields(metric.Name(), metric.Fields(), metric.Tags(), metric.Time())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isNagios {
|
||||||
|
metrics, err = nagios.TryAddState(runErr, metrics)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("E! [inputs.exec] failed to add nagios state: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range metrics {
|
||||||
|
acc.AddMetric(m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
|
||||||
"github.com/influxdata/telegraf/plugins/parsers"
|
"github.com/influxdata/telegraf/plugins/parsers"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf/testutil"
|
"github.com/influxdata/telegraf/testutil"
|
||||||
|
@ -75,21 +75,20 @@ var crTests = []CarriageReturnTest{
|
||||||
|
|
||||||
type runnerMock struct {
|
type runnerMock struct {
|
||||||
out []byte
|
out []byte
|
||||||
|
errout []byte
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRunnerMock(out []byte, err error) Runner {
|
func newRunnerMock(out []byte, errout []byte, err error) Runner {
|
||||||
return &runnerMock{
|
return &runnerMock{
|
||||||
out: out,
|
out: out,
|
||||||
|
errout: errout,
|
||||||
err: err,
|
err: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r runnerMock) Run(e *Exec, command string, acc telegraf.Accumulator) ([]byte, error) {
|
func (r runnerMock) Run(command string, _ time.Duration) ([]byte, []byte, error) {
|
||||||
if r.err != nil {
|
return r.out, r.errout, r.err
|
||||||
return nil, r.err
|
|
||||||
}
|
|
||||||
return r.out, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExec(t *testing.T) {
|
func TestExec(t *testing.T) {
|
||||||
|
@ -98,7 +97,7 @@ func TestExec(t *testing.T) {
|
||||||
MetricName: "exec",
|
MetricName: "exec",
|
||||||
})
|
})
|
||||||
e := &Exec{
|
e := &Exec{
|
||||||
runner: newRunnerMock([]byte(validJson), nil),
|
runner: newRunnerMock([]byte(validJson), nil, nil),
|
||||||
Commands: []string{"testcommand arg1"},
|
Commands: []string{"testcommand arg1"},
|
||||||
parser: parser,
|
parser: parser,
|
||||||
}
|
}
|
||||||
|
@ -127,7 +126,7 @@ func TestExecMalformed(t *testing.T) {
|
||||||
MetricName: "exec",
|
MetricName: "exec",
|
||||||
})
|
})
|
||||||
e := &Exec{
|
e := &Exec{
|
||||||
runner: newRunnerMock([]byte(malformedJson), nil),
|
runner: newRunnerMock([]byte(malformedJson), nil, nil),
|
||||||
Commands: []string{"badcommand arg1"},
|
Commands: []string{"badcommand arg1"},
|
||||||
parser: parser,
|
parser: parser,
|
||||||
}
|
}
|
||||||
|
@ -143,7 +142,7 @@ func TestCommandError(t *testing.T) {
|
||||||
MetricName: "exec",
|
MetricName: "exec",
|
||||||
})
|
})
|
||||||
e := &Exec{
|
e := &Exec{
|
||||||
runner: newRunnerMock(nil, fmt.Errorf("exit status code 1")),
|
runner: newRunnerMock(nil, nil, fmt.Errorf("exit status code 1")),
|
||||||
Commands: []string{"badcommand"},
|
Commands: []string{"badcommand"},
|
||||||
parser: parser,
|
parser: parser,
|
||||||
}
|
}
|
||||||
|
@ -201,6 +200,66 @@ func TestExecCommandWithoutGlobAndPath(t *testing.T) {
|
||||||
acc.AssertContainsFields(t, "metric", fields)
|
acc.AssertContainsFields(t, "metric", fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTruncate(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
bufF func() *bytes.Buffer
|
||||||
|
expF func() *bytes.Buffer
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "should not truncate",
|
||||||
|
bufF: func() *bytes.Buffer {
|
||||||
|
var b bytes.Buffer
|
||||||
|
b.WriteString("hello world")
|
||||||
|
return &b
|
||||||
|
},
|
||||||
|
expF: func() *bytes.Buffer {
|
||||||
|
var b bytes.Buffer
|
||||||
|
b.WriteString("hello world")
|
||||||
|
return &b
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "should truncate up to the new line",
|
||||||
|
bufF: func() *bytes.Buffer {
|
||||||
|
var b bytes.Buffer
|
||||||
|
b.WriteString("hello world\nand all the people")
|
||||||
|
return &b
|
||||||
|
},
|
||||||
|
expF: func() *bytes.Buffer {
|
||||||
|
var b bytes.Buffer
|
||||||
|
b.WriteString("hello world...")
|
||||||
|
return &b
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "should truncate to the MaxStderrBytes",
|
||||||
|
bufF: func() *bytes.Buffer {
|
||||||
|
var b bytes.Buffer
|
||||||
|
for i := 0; i < 2*MaxStderrBytes; i++ {
|
||||||
|
b.WriteByte('b')
|
||||||
|
}
|
||||||
|
return &b
|
||||||
|
},
|
||||||
|
expF: func() *bytes.Buffer {
|
||||||
|
var b bytes.Buffer
|
||||||
|
for i := 0; i < MaxStderrBytes; i++ {
|
||||||
|
b.WriteByte('b')
|
||||||
|
}
|
||||||
|
b.WriteString("...")
|
||||||
|
return &b
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
res := truncate(*tt.bufF())
|
||||||
|
require.Equal(t, tt.expF().Bytes(), res.Bytes())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRemoveCarriageReturns(t *testing.T) {
|
func TestRemoveCarriageReturns(t *testing.T) {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
// Test that all carriage returns are removed
|
// Test that all carriage returns are removed
|
||||||
|
|
|
@ -1,17 +1,78 @@
|
||||||
package nagios
|
package nagios
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
"github.com/influxdata/telegraf/metric"
|
"github.com/influxdata/telegraf/metric"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// getExitCode get the exit code from an error value which is the result
|
||||||
|
// of running a command through exec package api.
|
||||||
|
func getExitCode(err error) (int, error) {
|
||||||
|
if err == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ee, ok := err.(*exec.ExitError)
|
||||||
|
if !ok {
|
||||||
|
// If it is not an *exec.ExitError, then it must be
|
||||||
|
// an io error, but docs do not say anything about the
|
||||||
|
// exit code in this case.
|
||||||
|
return 0, errors.New("expected *exec.ExitError")
|
||||||
|
}
|
||||||
|
|
||||||
|
ws, ok := ee.Sys().(syscall.WaitStatus)
|
||||||
|
if !ok {
|
||||||
|
return 0, errors.New("expected syscall.WaitStatus")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ws.ExitStatus(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TryAddState attempts to add a state derived from the runErr.
|
||||||
|
// If any error occurs, it is guaranteed to be returned along with
|
||||||
|
// the initial metric slice.
|
||||||
|
func TryAddState(runErr error, metrics []telegraf.Metric) ([]telegraf.Metric, error) {
|
||||||
|
state, err := getExitCode(runErr)
|
||||||
|
if err != nil {
|
||||||
|
return metrics, fmt.Errorf("exec: get exit code: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range metrics {
|
||||||
|
if m.Name() == "nagios_state" {
|
||||||
|
m.AddField("state", state)
|
||||||
|
return metrics, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ts time.Time
|
||||||
|
if len(metrics) != 0 {
|
||||||
|
ts = metrics[0].Time()
|
||||||
|
} else {
|
||||||
|
ts = time.Now().UTC()
|
||||||
|
}
|
||||||
|
f := map[string]interface{}{
|
||||||
|
"state": state,
|
||||||
|
}
|
||||||
|
m, err := metric.New("nagios_state", nil, f, ts)
|
||||||
|
if err != nil {
|
||||||
|
return metrics, err
|
||||||
|
}
|
||||||
|
metrics = append(metrics, m)
|
||||||
|
return metrics, nil
|
||||||
|
}
|
||||||
|
|
||||||
type NagiosParser struct {
|
type NagiosParser struct {
|
||||||
MetricName string
|
MetricName string
|
||||||
DefaultTags map[string]string
|
DefaultTags map[string]string
|
||||||
|
@ -34,27 +95,88 @@ func (p *NagiosParser) SetDefaultTags(tags map[string]string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *NagiosParser) Parse(buf []byte) ([]telegraf.Metric, error) {
|
func (p *NagiosParser) Parse(buf []byte) ([]telegraf.Metric, error) {
|
||||||
|
ts := time.Now().UTC()
|
||||||
|
|
||||||
|
s := bufio.NewScanner(bytes.NewReader(buf))
|
||||||
|
|
||||||
|
var msg bytes.Buffer
|
||||||
|
var longmsg bytes.Buffer
|
||||||
|
|
||||||
metrics := make([]telegraf.Metric, 0)
|
metrics := make([]telegraf.Metric, 0)
|
||||||
lines := strings.Split(strings.TrimSpace(string(buf)), "\n")
|
|
||||||
|
|
||||||
for _, line := range lines {
|
// Scan the first line.
|
||||||
data_splitted := strings.Split(line, "|")
|
if !s.Scan() && s.Err() != nil {
|
||||||
|
return nil, s.Err()
|
||||||
if len(data_splitted) != 2 {
|
|
||||||
// got human readable output only or bad line
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
m, err := parsePerfData(data_splitted[1])
|
parts := bytes.Split(s.Bytes(), []byte{'|'})
|
||||||
|
switch len(parts) {
|
||||||
|
case 2:
|
||||||
|
ms, err := parsePerfData(string(parts[1]), ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("E! [parser.nagios] failed to parse performance data: %s\n", err.Error())
|
log.Printf("E! [parser.nagios] failed to parse performance data: %s\n", err.Error())
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
metrics = append(metrics, m...)
|
metrics = append(metrics, ms...)
|
||||||
|
fallthrough
|
||||||
|
case 1:
|
||||||
|
msg.Write(bytes.TrimSpace(parts[0]))
|
||||||
|
default:
|
||||||
|
return nil, errors.New("illegal output format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read long output.
|
||||||
|
for s.Scan() {
|
||||||
|
if bytes.Contains(s.Bytes(), []byte{'|'}) {
|
||||||
|
parts := bytes.Split(s.Bytes(), []byte{'|'})
|
||||||
|
if longmsg.Len() != 0 {
|
||||||
|
longmsg.WriteByte('\n')
|
||||||
|
}
|
||||||
|
longmsg.Write(bytes.TrimSpace(parts[0]))
|
||||||
|
|
||||||
|
ms, err := parsePerfData(string(parts[1]), ts)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("E! [parser.nagios] failed to parse performance data: %s\n", err.Error())
|
||||||
|
}
|
||||||
|
metrics = append(metrics, ms...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if longmsg.Len() != 0 {
|
||||||
|
longmsg.WriteByte('\n')
|
||||||
|
}
|
||||||
|
longmsg.Write(bytes.TrimSpace((s.Bytes())))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse extra performance data.
|
||||||
|
for s.Scan() {
|
||||||
|
ms, err := parsePerfData(s.Text(), ts)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("E! [parser.nagios] failed to parse performance data: %s\n", err.Error())
|
||||||
|
}
|
||||||
|
metrics = append(metrics, ms...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Err() != nil {
|
||||||
|
log.Printf("D! [parser.nagios] unexpected io error: %s\n", s.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create nagios state.
|
||||||
|
fields := map[string]interface{}{
|
||||||
|
"service_output": msg.String(),
|
||||||
|
}
|
||||||
|
if longmsg.Len() != 0 {
|
||||||
|
fields["long_service_output"] = longmsg.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := metric.New("nagios_state", nil, fields, ts)
|
||||||
|
if err == nil {
|
||||||
|
metrics = append(metrics, m)
|
||||||
|
} else {
|
||||||
|
log.Printf("E! [parser.nagios] failed to add nagios_state: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
return metrics, nil
|
return metrics, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePerfData(perfdatas string) ([]telegraf.Metric, error) {
|
func parsePerfData(perfdatas string, timestamp time.Time) ([]telegraf.Metric, error) {
|
||||||
metrics := make([]telegraf.Metric, 0)
|
metrics := make([]telegraf.Metric, 0)
|
||||||
|
|
||||||
for _, unParsedPerf := range perfSplitRegExp.FindAllString(perfdatas, -1) {
|
for _, unParsedPerf := range perfSplitRegExp.FindAllString(perfdatas, -1) {
|
||||||
|
@ -125,7 +247,7 @@ func parsePerfData(perfdatas string) ([]telegraf.Metric, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create metric
|
// Create metric
|
||||||
metric, err := metric.New("nagios", tags, fields, time.Now().UTC())
|
metric, err := metric.New("nagios", tags, fields, timestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,244 @@
|
||||||
package nagios
|
package nagios
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/influxdata/telegraf"
|
||||||
|
"github.com/influxdata/telegraf/metric"
|
||||||
|
"github.com/influxdata/telegraf/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const validOutput1 = `PING OK - Packet loss = 0%, RTA = 0.30 ms|rta=0.298000ms;4000.000000;6000.000000;0.000000 pl=0%;80;90;0;100
|
func TestGetExitCode(t *testing.T) {
|
||||||
This is a long output
|
tests := []struct {
|
||||||
with three lines
|
name string
|
||||||
`
|
errF func() error
|
||||||
const validOutput2 = "TCP OK - 0.008 second response time on port 80|time=0.008457s;;;0.000000;10.000000"
|
expCode int
|
||||||
const validOutput3 = "TCP OK - 0.008 second response time on port 80|time=0.008457"
|
expErr error
|
||||||
const validOutput4 = "OK: Load average: 0.00, 0.01, 0.05 | 'load1'=0.00;~:4;@0:6;0; 'load5'=0.01;3;0:5;0; 'load15'=0.05;0:2;0:4;0;"
|
}{
|
||||||
const invalidOutput3 = "PING OK - Packet loss = 0%, RTA = 0.30 ms"
|
{
|
||||||
const invalidOutput4 = "PING OK - Packet loss = 0%, RTA = 0.30 ms| =3;;;; dgasdg =;;;; sff=;;;;"
|
name: "nil error passed is ok",
|
||||||
|
errF: func() error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
expCode: 0,
|
||||||
|
expErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unexpected error type",
|
||||||
|
errF: func() error {
|
||||||
|
return errors.New("I am not *exec.ExitError")
|
||||||
|
},
|
||||||
|
expCode: 0,
|
||||||
|
expErr: errors.New("expected *exec.ExitError"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseValidOutput(t *testing.T) {
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
e := tt.errF()
|
||||||
|
code, err := getExitCode(e)
|
||||||
|
|
||||||
|
require.Equal(t, tt.expCode, code)
|
||||||
|
require.Equal(t, tt.expErr, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type metricBuilder struct {
|
||||||
|
name string
|
||||||
|
tags map[string]string
|
||||||
|
fields map[string]interface{}
|
||||||
|
timestamp time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func mb() *metricBuilder {
|
||||||
|
return &metricBuilder{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *metricBuilder) n(v string) *metricBuilder {
|
||||||
|
b.name = v
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *metricBuilder) t(k, v string) *metricBuilder {
|
||||||
|
if b.tags == nil {
|
||||||
|
b.tags = make(map[string]string)
|
||||||
|
}
|
||||||
|
b.tags[k] = v
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *metricBuilder) f(k string, v interface{}) *metricBuilder {
|
||||||
|
if b.fields == nil {
|
||||||
|
b.fields = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
b.fields[k] = v
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *metricBuilder) ts(v time.Time) *metricBuilder {
|
||||||
|
b.timestamp = v
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *metricBuilder) b() telegraf.Metric {
|
||||||
|
m, err := metric.New(b.name, b.tags, b.fields, b.timestamp)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertEqual asserts two slices to be equal. Note, that the order
|
||||||
|
// of the entries matters.
|
||||||
|
func assertEqual(t *testing.T, exp, actual []telegraf.Metric) {
|
||||||
|
require.Equal(t, len(exp), len(actual))
|
||||||
|
for i := 0; i < len(exp); i++ {
|
||||||
|
ok := testutil.MetricEqual(exp[i], actual[i])
|
||||||
|
require.True(t, ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTryAddState(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
runErrF func() error
|
||||||
|
metrics []telegraf.Metric
|
||||||
|
assertF func(*testing.T, []telegraf.Metric, error)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "should append state=0 field to existing metric",
|
||||||
|
runErrF: func() error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
metrics: []telegraf.Metric{
|
||||||
|
mb().
|
||||||
|
n("nagios").
|
||||||
|
f("perfdata", 0).b(),
|
||||||
|
mb().
|
||||||
|
n("nagios_state").
|
||||||
|
f("service_output", "OK: system working").b(),
|
||||||
|
},
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
|
exp := []telegraf.Metric{
|
||||||
|
mb().
|
||||||
|
n("nagios").
|
||||||
|
f("perfdata", 0).b(),
|
||||||
|
mb().
|
||||||
|
n("nagios_state").
|
||||||
|
f("service_output", "OK: system working").
|
||||||
|
f("state", 0).b(),
|
||||||
|
}
|
||||||
|
assertEqual(t, exp, metrics)
|
||||||
|
require.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "should create 'nagios_state state=0' and same timestamp as others",
|
||||||
|
runErrF: func() error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
metrics: []telegraf.Metric{
|
||||||
|
mb().
|
||||||
|
n("nagios").
|
||||||
|
f("perfdata", 0).b(),
|
||||||
|
},
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
|
exp := []telegraf.Metric{
|
||||||
|
mb().
|
||||||
|
n("nagios").
|
||||||
|
f("perfdata", 0).b(),
|
||||||
|
mb().
|
||||||
|
n("nagios_state").
|
||||||
|
f("state", 0).b(),
|
||||||
|
}
|
||||||
|
assertEqual(t, exp, metrics)
|
||||||
|
require.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "should create 'nagios_state state=0' and recent timestamp",
|
||||||
|
runErrF: func() error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
metrics: []telegraf.Metric{},
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
|
require.Len(t, metrics, 1)
|
||||||
|
m := metrics[0]
|
||||||
|
require.Equal(t, "nagios_state", m.Name())
|
||||||
|
s, ok := m.GetField("state")
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, int64(0), s)
|
||||||
|
require.WithinDuration(t, time.Now().UTC(), m.Time(), 10*time.Second)
|
||||||
|
require.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "should return original metrics and an error",
|
||||||
|
runErrF: func() error {
|
||||||
|
return errors.New("non parsable error")
|
||||||
|
},
|
||||||
|
metrics: []telegraf.Metric{
|
||||||
|
mb().
|
||||||
|
n("nagios").
|
||||||
|
f("perfdata", 0).b(),
|
||||||
|
},
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
|
exp := []telegraf.Metric{
|
||||||
|
mb().
|
||||||
|
n("nagios").
|
||||||
|
f("perfdata", 0).b(),
|
||||||
|
}
|
||||||
|
expErr := "exec: get exit code: expected *exec.ExitError"
|
||||||
|
|
||||||
|
assertEqual(t, exp, metrics)
|
||||||
|
require.Equal(t, expErr, err.Error())
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
metrics, err := TryAddState(tt.runErrF(), tt.metrics)
|
||||||
|
tt.assertF(t, metrics, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertNagiosState(t *testing.T, m telegraf.Metric, f map[string]interface{}) {
|
||||||
|
assert.Equal(t, map[string]string{}, m.Tags())
|
||||||
|
assert.Equal(t, f, m.Fields())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
parser := NagiosParser{
|
parser := NagiosParser{
|
||||||
MetricName: "nagios_test",
|
MetricName: "nagios_test",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output1
|
tests := []struct {
|
||||||
metrics, err := parser.Parse([]byte(validOutput1))
|
name string
|
||||||
|
input string
|
||||||
|
assertF func(*testing.T, []telegraf.Metric, error)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid output 1",
|
||||||
|
input: `PING OK - Packet loss = 0%, RTA = 0.30 ms|rta=0.298000ms;4000.000000;6000.000000;0.000000 pl=0%;80;90;0;100
|
||||||
|
This is a long output
|
||||||
|
with three lines
|
||||||
|
`,
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, metrics, 2)
|
require.Len(t, metrics, 3)
|
||||||
// rta
|
// rta
|
||||||
assert.Equal(t, "rta", metrics[0].Tags()["perfdata"])
|
assert.Equal(t, map[string]string{
|
||||||
|
"unit": "ms",
|
||||||
|
"perfdata": "rta",
|
||||||
|
}, metrics[0].Tags())
|
||||||
assert.Equal(t, map[string]interface{}{
|
assert.Equal(t, map[string]interface{}{
|
||||||
"value": float64(0.298),
|
"value": float64(0.298),
|
||||||
"warning_lt": float64(0),
|
"warning_lt": float64(0),
|
||||||
|
@ -36,9 +247,12 @@ func TestParseValidOutput(t *testing.T) {
|
||||||
"critical_gt": float64(6000),
|
"critical_gt": float64(6000),
|
||||||
"min": float64(0),
|
"min": float64(0),
|
||||||
}, metrics[0].Fields())
|
}, metrics[0].Fields())
|
||||||
assert.Equal(t, map[string]string{"unit": "ms", "perfdata": "rta"}, metrics[0].Tags())
|
|
||||||
// pl
|
// pl
|
||||||
assert.Equal(t, "pl", metrics[1].Tags()["perfdata"])
|
assert.Equal(t, map[string]string{
|
||||||
|
"unit": "%",
|
||||||
|
"perfdata": "pl",
|
||||||
|
}, metrics[1].Tags())
|
||||||
assert.Equal(t, map[string]interface{}{
|
assert.Equal(t, map[string]interface{}{
|
||||||
"value": float64(0),
|
"value": float64(0),
|
||||||
"warning_lt": float64(0),
|
"warning_lt": float64(0),
|
||||||
|
@ -48,38 +262,64 @@ func TestParseValidOutput(t *testing.T) {
|
||||||
"min": float64(0),
|
"min": float64(0),
|
||||||
"max": float64(100),
|
"max": float64(100),
|
||||||
}, metrics[1].Fields())
|
}, metrics[1].Fields())
|
||||||
assert.Equal(t, map[string]string{"unit": "%", "perfdata": "pl"}, metrics[1].Tags())
|
|
||||||
|
|
||||||
// Output2
|
assertNagiosState(t, metrics[2], map[string]interface{}{
|
||||||
metrics, err = parser.Parse([]byte(validOutput2))
|
"service_output": "PING OK - Packet loss = 0%, RTA = 0.30 ms",
|
||||||
|
"long_service_output": "This is a long output\nwith three lines",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid output 2",
|
||||||
|
input: "TCP OK - 0.008 second response time on port 80|time=0.008457s;;;0.000000;10.000000",
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, metrics, 1)
|
require.Len(t, metrics, 2)
|
||||||
// time
|
// time
|
||||||
assert.Equal(t, "time", metrics[0].Tags()["perfdata"])
|
assert.Equal(t, map[string]string{
|
||||||
|
"unit": "s",
|
||||||
|
"perfdata": "time",
|
||||||
|
}, metrics[0].Tags())
|
||||||
assert.Equal(t, map[string]interface{}{
|
assert.Equal(t, map[string]interface{}{
|
||||||
"value": float64(0.008457),
|
"value": float64(0.008457),
|
||||||
"min": float64(0),
|
"min": float64(0),
|
||||||
"max": float64(10),
|
"max": float64(10),
|
||||||
}, metrics[0].Fields())
|
}, metrics[0].Fields())
|
||||||
assert.Equal(t, map[string]string{"unit": "s", "perfdata": "time"}, metrics[0].Tags())
|
|
||||||
|
|
||||||
// Output3
|
assertNagiosState(t, metrics[1], map[string]interface{}{
|
||||||
metrics, err = parser.Parse([]byte(validOutput3))
|
"service_output": "TCP OK - 0.008 second response time on port 80",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid output 3",
|
||||||
|
input: "TCP OK - 0.008 second response time on port 80|time=0.008457",
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, metrics, 1)
|
require.Len(t, metrics, 2)
|
||||||
// time
|
// time
|
||||||
assert.Equal(t, "time", metrics[0].Tags()["perfdata"])
|
assert.Equal(t, map[string]string{
|
||||||
|
"perfdata": "time",
|
||||||
|
}, metrics[0].Tags())
|
||||||
assert.Equal(t, map[string]interface{}{
|
assert.Equal(t, map[string]interface{}{
|
||||||
"value": float64(0.008457),
|
"value": float64(0.008457),
|
||||||
}, metrics[0].Fields())
|
}, metrics[0].Fields())
|
||||||
assert.Equal(t, map[string]string{"perfdata": "time"}, metrics[0].Tags())
|
|
||||||
|
|
||||||
// Output4
|
assertNagiosState(t, metrics[1], map[string]interface{}{
|
||||||
metrics, err = parser.Parse([]byte(validOutput4))
|
"service_output": "TCP OK - 0.008 second response time on port 80",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid output 4",
|
||||||
|
input: "OK: Load average: 0.00, 0.01, 0.05 | 'load1'=0.00;~:4;@0:6;0; 'load5'=0.01;3;0:5;0; 'load15'=0.05;0:2;0:4;0;",
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, metrics, 3)
|
require.Len(t, metrics, 4)
|
||||||
// load
|
// load1
|
||||||
// const validOutput4 = "OK: Load average: 0.00, 0.01, 0.05 | 'load1'=0.00;0:4;0:6;0; 'load5'=0.01;0:3;0:5;0; 'load15'=0.05;0:2;0:4;0;"
|
assert.Equal(t, map[string]string{
|
||||||
|
"perfdata": "load1",
|
||||||
|
}, metrics[0].Tags())
|
||||||
assert.Equal(t, map[string]interface{}{
|
assert.Equal(t, map[string]interface{}{
|
||||||
"value": float64(0.00),
|
"value": float64(0.00),
|
||||||
"warning_lt": MinFloat64,
|
"warning_lt": MinFloat64,
|
||||||
|
@ -89,24 +329,148 @@ func TestParseValidOutput(t *testing.T) {
|
||||||
"min": float64(0),
|
"min": float64(0),
|
||||||
}, metrics[0].Fields())
|
}, metrics[0].Fields())
|
||||||
|
|
||||||
assert.Equal(t, map[string]string{"perfdata": "load1"}, metrics[0].Tags())
|
// load5
|
||||||
|
assert.Equal(t, map[string]string{
|
||||||
|
"perfdata": "load5",
|
||||||
|
}, metrics[1].Tags())
|
||||||
|
assert.Equal(t, map[string]interface{}{
|
||||||
|
"value": float64(0.01),
|
||||||
|
"warning_gt": float64(3),
|
||||||
|
"warning_lt": float64(0),
|
||||||
|
"critical_lt": float64(0),
|
||||||
|
"critical_gt": float64(5),
|
||||||
|
"min": float64(0),
|
||||||
|
}, metrics[1].Fields())
|
||||||
|
|
||||||
|
// load15
|
||||||
|
assert.Equal(t, map[string]string{
|
||||||
|
"perfdata": "load15",
|
||||||
|
}, metrics[2].Tags())
|
||||||
|
assert.Equal(t, map[string]interface{}{
|
||||||
|
"value": float64(0.05),
|
||||||
|
"warning_lt": float64(0),
|
||||||
|
"warning_gt": float64(2),
|
||||||
|
"critical_lt": float64(0),
|
||||||
|
"critical_gt": float64(4),
|
||||||
|
"min": float64(0),
|
||||||
|
}, metrics[2].Fields())
|
||||||
|
|
||||||
|
assertNagiosState(t, metrics[3], map[string]interface{}{
|
||||||
|
"service_output": "OK: Load average: 0.00, 0.01, 0.05",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no perf data",
|
||||||
|
input: "PING OK - Packet loss = 0%, RTA = 0.30 ms",
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, metrics, 1)
|
||||||
|
|
||||||
|
assertNagiosState(t, metrics[0], map[string]interface{}{
|
||||||
|
"service_output": "PING OK - Packet loss = 0%, RTA = 0.30 ms",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "malformed perf data",
|
||||||
|
input: "PING OK - Packet loss = 0%, RTA = 0.30 ms| =3;;;; dgasdg =;;;; sff=;;;;",
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, metrics, 1)
|
||||||
|
|
||||||
|
assertNagiosState(t, metrics[0], map[string]interface{}{
|
||||||
|
"service_output": "PING OK - Packet loss = 0%, RTA = 0.30 ms",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "from https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/pluginapi.html",
|
||||||
|
input: `DISK OK - free space: / 3326 MB (56%); | /=2643MB;5948;5958;0;5968
|
||||||
|
/ 15272 MB (77%);
|
||||||
|
/boot 68 MB (69%);
|
||||||
|
/home 69357 MB (27%);
|
||||||
|
/var/log 819 MB (84%); | /boot=68MB;88;93;0;98
|
||||||
|
/home=69357MB;253404;253409;0;253414
|
||||||
|
/var/log=818MB;970;975;0;980
|
||||||
|
`,
|
||||||
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, metrics, 5)
|
||||||
|
// /=2643MB;5948;5958;0;5968
|
||||||
|
assert.Equal(t, map[string]string{
|
||||||
|
"unit": "MB",
|
||||||
|
"perfdata": "/",
|
||||||
|
}, metrics[0].Tags())
|
||||||
|
assert.Equal(t, map[string]interface{}{
|
||||||
|
"value": float64(2643),
|
||||||
|
"warning_lt": float64(0),
|
||||||
|
"warning_gt": float64(5948),
|
||||||
|
"critical_lt": float64(0),
|
||||||
|
"critical_gt": float64(5958),
|
||||||
|
"min": float64(0),
|
||||||
|
"max": float64(5968),
|
||||||
|
}, metrics[0].Fields())
|
||||||
|
|
||||||
|
// /boot=68MB;88;93;0;98
|
||||||
|
assert.Equal(t, map[string]string{
|
||||||
|
"unit": "MB",
|
||||||
|
"perfdata": "/boot",
|
||||||
|
}, metrics[1].Tags())
|
||||||
|
assert.Equal(t, map[string]interface{}{
|
||||||
|
"value": float64(68),
|
||||||
|
"warning_lt": float64(0),
|
||||||
|
"warning_gt": float64(88),
|
||||||
|
"critical_lt": float64(0),
|
||||||
|
"critical_gt": float64(93),
|
||||||
|
"min": float64(0),
|
||||||
|
"max": float64(98),
|
||||||
|
}, metrics[1].Fields())
|
||||||
|
|
||||||
|
// /home=69357MB;253404;253409;0;253414
|
||||||
|
assert.Equal(t, map[string]string{
|
||||||
|
"unit": "MB",
|
||||||
|
"perfdata": "/home",
|
||||||
|
}, metrics[2].Tags())
|
||||||
|
assert.Equal(t, map[string]interface{}{
|
||||||
|
"value": float64(69357),
|
||||||
|
"warning_lt": float64(0),
|
||||||
|
"warning_gt": float64(253404),
|
||||||
|
"critical_lt": float64(0),
|
||||||
|
"critical_gt": float64(253409),
|
||||||
|
"min": float64(0),
|
||||||
|
"max": float64(253414),
|
||||||
|
}, metrics[2].Fields())
|
||||||
|
|
||||||
|
// /var/log=818MB;970;975;0;980
|
||||||
|
assert.Equal(t, map[string]string{
|
||||||
|
"unit": "MB",
|
||||||
|
"perfdata": "/var/log",
|
||||||
|
}, metrics[3].Tags())
|
||||||
|
assert.Equal(t, map[string]interface{}{
|
||||||
|
"value": float64(818),
|
||||||
|
"warning_lt": float64(0),
|
||||||
|
"warning_gt": float64(970),
|
||||||
|
"critical_lt": float64(0),
|
||||||
|
"critical_gt": float64(975),
|
||||||
|
"min": float64(0),
|
||||||
|
"max": float64(980),
|
||||||
|
}, metrics[3].Fields())
|
||||||
|
|
||||||
|
assertNagiosState(t, metrics[4], map[string]interface{}{
|
||||||
|
"service_output": "DISK OK - free space: / 3326 MB (56%);",
|
||||||
|
"long_service_output": "/ 15272 MB (77%);\n/boot 68 MB (69%);\n/home 69357 MB (27%);\n/var/log 819 MB (84%);",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseInvalidOutput(t *testing.T) {
|
for _, tt := range tests {
|
||||||
parser := NagiosParser{
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
MetricName: "nagios_test",
|
metrics, err := parser.Parse([]byte(tt.input))
|
||||||
|
tt.assertF(t, metrics, err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalidOutput3
|
|
||||||
metrics, err := parser.Parse([]byte(invalidOutput3))
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, metrics, 0)
|
|
||||||
|
|
||||||
// invalidOutput4
|
|
||||||
metrics, err = parser.Parse([]byte(invalidOutput4))
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, metrics, 0)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseThreshold(t *testing.T) {
|
func TestParseThreshold(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue