telegraf/plugins/parsers/nagios/parser.go

123 lines
3.1 KiB
Go
Raw Permalink Normal View History

package nagios
import (
"regexp"
"strconv"
"strings"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
)
type NagiosParser struct {
MetricName string
DefaultTags map[string]string
}
// Got from Alignak
// https://github.com/Alignak-monitoring/alignak/blob/develop/alignak/misc/perfdata.py
var perfSplitRegExp, _ = regexp.Compile(`([^=]+=\S+)`)
var nagiosRegExp, _ = regexp.Compile(`^([^=]+)=([\d\.\-\+eE]+)([\w\/%]*);?([\d\.\-\+eE:~@]+)?;?([\d\.\-\+eE:~@]+)?;?([\d\.\-\+eE]+)?;?([\d\.\-\+eE]+)?;?\s*`)
func (p *NagiosParser) ParseLine(line string) (telegraf.Metric, error) {
metrics, err := p.Parse([]byte(line))
return metrics[0], err
}
func (p *NagiosParser) SetDefaultTags(tags map[string]string) {
p.DefaultTags = tags
}
//> rta,host=absol,unit=ms critical=6000,min=0,value=0.332,warning=4000 1456374625003628099
//> pl,host=absol,unit=% critical=90,min=0,value=0,warning=80 1456374625003693967
func (p *NagiosParser) Parse(buf []byte) ([]telegraf.Metric, error) {
metrics := make([]telegraf.Metric, 0)
// Convert to string
out := string(buf)
// Prepare output for splitting
// Delete escaped pipes
out = strings.Replace(out, `\|`, "___PROTECT_PIPE___", -1)
// Split lines and get the first one
lines := strings.Split(out, "\n")
// Split output and perfdatas
data_splitted := strings.Split(lines[0], "|")
if len(data_splitted) <= 1 {
// No pipe == no perf data
return nil, nil
}
// Get perfdatas
perfdatas := data_splitted[1]
// Add escaped pipes
perfdatas = strings.Replace(perfdatas, "___PROTECT_PIPE___", `\|`, -1)
// Split perfs
unParsedPerfs := perfSplitRegExp.FindAllSubmatch([]byte(perfdatas), -1)
// Iterate on all perfs
for _, unParsedPerfs := range unParsedPerfs {
// Get metrics
// Trim perf
trimedPerf := strings.Trim(string(unParsedPerfs[0]), " ")
// Parse perf
perf := nagiosRegExp.FindAllSubmatch([]byte(trimedPerf), -1)
// Bad string
if len(perf) == 0 {
continue
}
if len(perf[0]) <= 2 {
continue
}
if perf[0][1] == nil || perf[0][2] == nil {
continue
}
fieldName := string(perf[0][1])
tags := make(map[string]string)
if perf[0][3] != nil {
str := string(perf[0][3])
if str != "" {
tags["unit"] = str
}
}
fields := make(map[string]interface{})
f, err := strconv.ParseFloat(string(perf[0][2]), 64)
if err == nil {
fields["value"] = f
}
// TODO should we set empty field
// if metric if there is no data ?
if perf[0][4] != nil {
f, err := strconv.ParseFloat(string(perf[0][4]), 64)
if err == nil {
fields["warning"] = f
}
}
if perf[0][5] != nil {
f, err := strconv.ParseFloat(string(perf[0][5]), 64)
if err == nil {
fields["critical"] = f
}
}
if perf[0][6] != nil {
f, err := strconv.ParseFloat(string(perf[0][6]), 64)
if err == nil {
fields["min"] = f
}
}
if perf[0][7] != nil {
f, err := strconv.ParseFloat(string(perf[0][7]), 64)
if err == nil {
fields["max"] = f
}
}
// Create metric
metric, err := metric.New(fieldName, tags, fields, time.Now().UTC())
if err != nil {
return nil, err
}
// Add Metric
metrics = append(metrics, metric)
}
return metrics, nil
}