telegraf/plugins/processors/parser/parser_test.go

718 lines
17 KiB
Go
Raw Normal View History

2018-08-23 07:28:50 +08:00
package parser
import (
"testing"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
"github.com/stretchr/testify/require"
//Blank import to register all new-style parsers
"github.com/influxdata/telegraf/plugins/parsers/grok"
"github.com/influxdata/telegraf/plugins/parsers/influx"
"github.com/influxdata/telegraf/plugins/parsers/json"
"github.com/influxdata/telegraf/plugins/parsers/logfmt"
"github.com/influxdata/telegraf/testutil"
2018-08-23 07:28:50 +08:00
)
func TestApply(t *testing.T) {
tests := []struct {
name string
parseFields []string
parseTags []string
parser telegraf.Parser
2018-08-23 07:28:50 +08:00
dropOriginal bool
merge string
input telegraf.Metric
expected []telegraf.Metric
}{
{
name: "parse one field drop original",
parseFields: []string{"sample"},
dropOriginal: true,
parser: &json.Parser{
2018-08-23 07:28:50 +08:00
TagKeys: []string{
"ts",
"lvl",
"msg",
"method",
},
},
input: metric.New(
"singleField",
map[string]string{
"some": "tag",
},
map[string]interface{}{
"sample": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"singleField",
map[string]string{
"ts": "2018-07-24T19:43:40.275Z",
"lvl": "info",
"msg": "http request",
"method": "POST",
},
map[string]interface{}{},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "parse one field with merge",
parseFields: []string{"sample"},
dropOriginal: false,
merge: "override",
parser: &json.Parser{
2018-08-23 07:28:50 +08:00
TagKeys: []string{
"ts",
"lvl",
"msg",
"method",
},
},
input: metric.New(
"singleField",
map[string]string{
"some": "tag",
},
map[string]interface{}{
"sample": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"singleField",
map[string]string{
"some": "tag",
"ts": "2018-07-24T19:43:40.275Z",
"lvl": "info",
"msg": "http request",
"method": "POST",
},
map[string]interface{}{
"sample": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "parse one field keep",
parseFields: []string{"sample"},
dropOriginal: false,
parser: &json.Parser{
2018-08-23 07:28:50 +08:00
TagKeys: []string{
"ts",
"lvl",
"msg",
"method",
},
},
input: metric.New(
"singleField",
map[string]string{
"some": "tag",
},
map[string]interface{}{
"sample": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"singleField",
map[string]string{
"some": "tag",
},
map[string]interface{}{
"sample": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
},
time.Unix(0, 0)),
metric.New(
2018-08-23 07:28:50 +08:00
"singleField",
map[string]string{
"ts": "2018-07-24T19:43:40.275Z",
"lvl": "info",
"msg": "http request",
"method": "POST",
},
map[string]interface{}{},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "parse one field keep with measurement name",
parseFields: []string{"message"},
parser: &influx.Parser{},
2018-08-23 07:28:50 +08:00
dropOriginal: false,
input: metric.New(
"influxField",
map[string]string{},
map[string]interface{}{
"message": "deal,computer_name=hosta message=\"stuff\" 1530654676316265790",
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"influxField",
map[string]string{},
map[string]interface{}{
"message": "deal,computer_name=hosta message=\"stuff\" 1530654676316265790",
},
time.Unix(0, 0)),
metric.New(
2018-08-23 07:28:50 +08:00
"deal",
map[string]string{
"computer_name": "hosta",
},
map[string]interface{}{
"message": "stuff",
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "parse one field override replaces name",
parseFields: []string{"message"},
dropOriginal: false,
merge: "override",
parser: &influx.Parser{},
input: metric.New(
"influxField",
map[string]string{
"some": "tag",
},
map[string]interface{}{
"message": "deal,computer_name=hosta message=\"stuff\" 1530654676316265790",
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"deal",
map[string]string{
"computer_name": "hosta",
"some": "tag",
},
map[string]interface{}{
"message": "stuff",
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "parse grok field",
parseFields: []string{"grokSample"},
dropOriginal: true,
parser: &grok.Parser{
Patterns: []string{"%{COMBINED_LOG_FORMAT}"},
2018-08-23 07:28:50 +08:00
},
input: metric.New(
"success",
map[string]string{},
map[string]interface{}{
"grokSample": "127.0.0.1 - - [11/Dec/2013:00:01:45 -0800] \"GET /xampp/status.php HTTP/1.1\" 200 3891 \"http://cadenza/xampp/navi.php\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:25.0) Gecko/20100101 Firefox/25.0\"",
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"success",
map[string]string{
"resp_code": "200",
"verb": "GET",
},
map[string]interface{}{
"resp_bytes": int64(3891),
"auth": "-",
"request": "/xampp/status.php",
"referrer": "http://cadenza/xampp/navi.php",
"agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:25.0) Gecko/20100101 Firefox/25.0",
"client_ip": "127.0.0.1",
"ident": "-",
"http_version": float64(1.1),
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "parse two fields [replace]",
parseFields: []string{"field_1", "field_2"},
dropOriginal: true,
parser: &json.Parser{
TagKeys: []string{"lvl", "err"},
2018-08-23 07:28:50 +08:00
},
input: metric.New(
"bigMeasure",
map[string]string{},
map[string]interface{}{
"field_1": `{"lvl":"info","msg":"http request"}`,
"field_2": `{"err":"fatal","fatal":"security threat"}`,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"bigMeasure",
map[string]string{
"lvl": "info",
},
map[string]interface{}{},
time.Unix(0, 0)),
metric.New(
2018-08-23 07:28:50 +08:00
"bigMeasure",
map[string]string{
"err": "fatal",
},
map[string]interface{}{},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "parse two fields [merge]",
parseFields: []string{"field_1", "field_2"},
dropOriginal: false,
merge: "override",
parser: &json.Parser{
TagKeys: []string{"lvl", "msg", "err", "fatal"},
2018-08-23 07:28:50 +08:00
},
input: metric.New(
"bigMeasure",
map[string]string{},
map[string]interface{}{
"field_1": `{"lvl":"info","msg":"http request"}`,
"field_2": `{"err":"fatal","fatal":"security threat"}`,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"bigMeasure",
map[string]string{
"lvl": "info",
"msg": "http request",
"err": "fatal",
"fatal": "security threat",
},
map[string]interface{}{
"field_1": `{"lvl":"info","msg":"http request"}`,
"field_2": `{"err":"fatal","fatal":"security threat"}`,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "parse two fields [keep]",
parseFields: []string{"field_1", "field_2"},
dropOriginal: false,
parser: &json.Parser{
TagKeys: []string{"lvl", "msg", "err", "fatal"},
2018-08-23 07:28:50 +08:00
},
input: metric.New(
"bigMeasure",
map[string]string{},
map[string]interface{}{
"field_1": `{"lvl":"info","msg":"http request"}`,
"field_2": `{"err":"fatal","fatal":"security threat"}`,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"bigMeasure",
map[string]string{},
map[string]interface{}{
"field_1": `{"lvl":"info","msg":"http request"}`,
"field_2": `{"err":"fatal","fatal":"security threat"}`,
},
time.Unix(0, 0)),
metric.New(
2018-08-23 07:28:50 +08:00
"bigMeasure",
map[string]string{
"lvl": "info",
"msg": "http request",
},
map[string]interface{}{},
time.Unix(0, 0)),
metric.New(
2018-08-23 07:28:50 +08:00
"bigMeasure",
map[string]string{
"err": "fatal",
"fatal": "security threat",
},
map[string]interface{}{},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "parse one tag drop original",
parseTags: []string{"sample"},
dropOriginal: true,
parser: &logfmt.Parser{},
input: metric.New(
"singleTag",
map[string]string{
"some": "tag",
"sample": `ts=2018-07-24T19:43:40.275Z`,
},
map[string]interface{}{},
time.Unix(0, 0)),
expected: []telegraf.Metric{
metric.New(
"singleTag",
map[string]string{},
map[string]interface{}{
"ts": "2018-07-24T19:43:40.275Z",
},
time.Unix(0, 0)),
},
},
{
name: "parse one tag with merge",
parseTags: []string{"sample"},
dropOriginal: false,
merge: "override",
parser: &logfmt.Parser{},
input: metric.New(
"singleTag",
map[string]string{
"some": "tag",
"sample": `ts=2018-07-24T19:43:40.275Z`,
},
map[string]interface{}{},
time.Unix(0, 0)),
expected: []telegraf.Metric{
metric.New(
"singleTag",
map[string]string{
"some": "tag",
"sample": `ts=2018-07-24T19:43:40.275Z`,
},
map[string]interface{}{
"ts": "2018-07-24T19:43:40.275Z",
},
time.Unix(0, 0)),
},
},
{
name: "parse one tag keep",
parseTags: []string{"sample"},
dropOriginal: false,
parser: &logfmt.Parser{},
input: metric.New(
"singleTag",
map[string]string{
"some": "tag",
"sample": `ts=2018-07-24T19:43:40.275Z`,
},
map[string]interface{}{},
time.Unix(0, 0)),
expected: []telegraf.Metric{
metric.New(
"singleTag",
map[string]string{
"some": "tag",
"sample": `ts=2018-07-24T19:43:40.275Z`,
},
map[string]interface{}{},
time.Unix(0, 0)),
metric.New(
"singleTag",
map[string]string{},
map[string]interface{}{
"ts": "2018-07-24T19:43:40.275Z",
},
time.Unix(0, 0)),
},
},
2018-08-23 07:28:50 +08:00
{
name: "Fail to parse one field but parses other [keep]",
parseFields: []string{"good", "bad"},
dropOriginal: false,
parser: &json.Parser{
TagKeys: []string{"lvl"},
2018-08-23 07:28:50 +08:00
},
input: metric.New(
"success",
map[string]string{},
map[string]interface{}{
"good": `{"lvl":"info"}`,
"bad": "why",
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"success",
map[string]string{},
map[string]interface{}{
"good": `{"lvl":"info"}`,
"bad": "why",
},
time.Unix(0, 0)),
metric.New(
2018-08-23 07:28:50 +08:00
"success",
map[string]string{
"lvl": "info",
},
map[string]interface{}{},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "Fail to parse one field but parses other [keep] v2",
parseFields: []string{"bad", "good", "ok"},
dropOriginal: false,
parser: &json.Parser{
TagKeys: []string{"lvl", "thing"},
2018-08-23 07:28:50 +08:00
},
input: metric.New(
"success",
map[string]string{},
map[string]interface{}{
"bad": "why",
"good": `{"lvl":"info"}`,
"ok": `{"thing":"thang"}`,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"success",
map[string]string{},
map[string]interface{}{
"bad": "why",
"good": `{"lvl":"info"}`,
"ok": `{"thing":"thang"}`,
},
time.Unix(0, 0)),
metric.New(
2018-08-23 07:28:50 +08:00
"success",
map[string]string{
"lvl": "info",
},
map[string]interface{}{},
time.Unix(0, 0)),
metric.New(
2018-08-23 07:28:50 +08:00
"success",
map[string]string{
"thing": "thang",
},
map[string]interface{}{},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "Fail to parse one field but parses other [merge]",
parseFields: []string{"good", "bad"},
dropOriginal: false,
merge: "override",
parser: &json.Parser{
TagKeys: []string{"lvl"},
2018-08-23 07:28:50 +08:00
},
input: metric.New(
"success",
map[string]string{
"a": "tag",
},
map[string]interface{}{
"good": `{"lvl":"info"}`,
"bad": "why",
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"success",
map[string]string{
"a": "tag",
"lvl": "info",
},
map[string]interface{}{
"good": `{"lvl":"info"}`,
"bad": "why",
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "Fail to parse one field but parses other [replace]",
parseFields: []string{"good", "bad"},
dropOriginal: true,
parser: &json.Parser{
TagKeys: []string{"lvl"},
2018-08-23 07:28:50 +08:00
},
input: metric.New(
"success",
map[string]string{
"thing": "tag",
},
map[string]interface{}{
"good": `{"lvl":"info"}`,
"bad": "why",
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"success",
map[string]string{
"lvl": "info",
},
map[string]interface{}{},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if p, ok := tt.parser.(telegraf.Initializer); ok {
require.NoError(t, p.Init())
}
plugin := Parser{
2018-08-23 07:28:50 +08:00
ParseFields: tt.parseFields,
ParseTags: tt.parseTags,
2018-08-23 07:28:50 +08:00
DropOriginal: tt.dropOriginal,
Merge: tt.merge,
Log: testutil.Logger{Name: "processor.parser"},
2018-08-23 07:28:50 +08:00
}
plugin.SetParser(tt.parser)
2018-08-23 07:28:50 +08:00
output := plugin.Apply(tt.input)
2018-08-23 07:28:50 +08:00
t.Logf("Testing: %s", tt.name)
testutil.RequireMetricsEqual(t, tt.expected, output, testutil.IgnoreTime())
2018-08-23 07:28:50 +08:00
})
}
}
func TestBadApply(t *testing.T) {
tests := []struct {
name string
parseFields []string
parser telegraf.Parser
2018-08-23 07:28:50 +08:00
input telegraf.Metric
expected []telegraf.Metric
}{
{
name: "field not found",
parseFields: []string{"bad_field"},
parser: &json.Parser{},
input: metric.New(
"bad",
map[string]string{},
map[string]interface{}{
"some_field": 5,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"bad",
map[string]string{},
map[string]interface{}{
"some_field": 5,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
{
name: "non string field",
parseFields: []string{"some_field"},
parser: &json.Parser{},
input: metric.New(
"bad",
map[string]string{},
map[string]interface{}{
"some_field": 5,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
expected: []telegraf.Metric{
metric.New(
2018-08-23 07:28:50 +08:00
"bad",
map[string]string{},
map[string]interface{}{
"some_field": 5,
},
time.Unix(0, 0)),
2018-08-23 07:28:50 +08:00
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if p, ok := tt.parser.(telegraf.Initializer); ok {
require.NoError(t, p.Init())
}
plugin := Parser{
2018-08-23 07:28:50 +08:00
ParseFields: tt.parseFields,
Log: testutil.Logger{Name: "processor.parser"},
2018-08-23 07:28:50 +08:00
}
plugin.SetParser(tt.parser)
2018-08-23 07:28:50 +08:00
output := plugin.Apply(tt.input)
testutil.RequireMetricsEqual(t, tt.expected, output, testutil.IgnoreTime())
2018-08-23 07:28:50 +08:00
})
}
}
// Benchmarks
func getMetricFields(m telegraf.Metric) interface{} {
2018-08-23 07:28:50 +08:00
key := "field3"
if value, ok := m.Fields()[key]; ok {
2018-08-23 07:28:50 +08:00
return value
}
return nil
}
func getMetricFieldList(m telegraf.Metric) interface{} {
2018-08-23 07:28:50 +08:00
key := "field3"
fields := m.FieldList()
2018-08-23 07:28:50 +08:00
for _, field := range fields {
if field.Key == key {
return field.Value
}
}
return nil
}
func BenchmarkFieldListing(b *testing.B) {
m := metric.New(
2018-08-23 07:28:50 +08:00
"test",
map[string]string{
"some": "tag",
},
map[string]interface{}{
"field0": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field1": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field2": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field3": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field4": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field5": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field6": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
},
time.Unix(0, 0))
2018-08-23 07:28:50 +08:00
for n := 0; n < b.N; n++ {
getMetricFieldList(m)
2018-08-23 07:28:50 +08:00
}
}
func BenchmarkFields(b *testing.B) {
m := metric.New(
2018-08-23 07:28:50 +08:00
"test",
map[string]string{
"some": "tag",
},
map[string]interface{}{
"field0": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field1": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field2": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field3": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field4": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field5": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
"field6": `{"ts":"2018-07-24T19:43:40.275Z","lvl":"info","msg":"http request","method":"POST"}`,
},
time.Unix(0, 0))
2018-08-23 07:28:50 +08:00
for n := 0; n < b.N; n++ {
getMetricFields(m)
2018-08-23 07:28:50 +08:00
}
}