Add regex processor plugin (#3839)
This commit is contained in:
committed by
Daniel Nelson
parent
3be9cad309
commit
ccc4a85fd6
273
plugins/processors/regex/regex_test.go
Normal file
273
plugins/processors/regex/regex_test.go
Normal file
@@ -0,0 +1,273 @@
|
||||
package regex
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/metric"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func newM1() telegraf.Metric {
|
||||
m1, _ := metric.New("access_log",
|
||||
map[string]string{
|
||||
"verb": "GET",
|
||||
"resp_code": "200",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"request": "/users/42/",
|
||||
},
|
||||
time.Now(),
|
||||
)
|
||||
return m1
|
||||
}
|
||||
|
||||
func newM2() telegraf.Metric {
|
||||
m2, _ := metric.New("access_log",
|
||||
map[string]string{
|
||||
"verb": "GET",
|
||||
"resp_code": "200",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"request": "/api/search/?category=plugins&q=regex&sort=asc",
|
||||
"ignore_number": int64(200),
|
||||
"ignore_bool": true,
|
||||
},
|
||||
time.Now(),
|
||||
)
|
||||
return m2
|
||||
}
|
||||
|
||||
func TestFieldConversions(t *testing.T) {
|
||||
tests := []struct {
|
||||
message string
|
||||
converter converter
|
||||
expectedFields map[string]interface{}
|
||||
}{
|
||||
{
|
||||
message: "Should change existing field",
|
||||
converter: converter{
|
||||
Key: "request",
|
||||
Pattern: "^/users/\\d+/$",
|
||||
Replacement: "/users/{id}/",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"request": "/users/{id}/",
|
||||
},
|
||||
},
|
||||
{
|
||||
message: "Should add new field",
|
||||
converter: converter{
|
||||
Key: "request",
|
||||
Pattern: "^/users/\\d+/$",
|
||||
Replacement: "/users/{id}/",
|
||||
ResultKey: "normalized_request",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"request": "/users/42/",
|
||||
"normalized_request": "/users/{id}/",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
regex := NewRegex()
|
||||
regex.Fields = []converter{
|
||||
test.converter,
|
||||
}
|
||||
|
||||
processed := regex.Apply(newM1())
|
||||
|
||||
expectedTags := map[string]string{
|
||||
"verb": "GET",
|
||||
"resp_code": "200",
|
||||
}
|
||||
|
||||
assert.Equal(t, test.expectedFields, processed[0].Fields(), test.message)
|
||||
assert.Equal(t, expectedTags, processed[0].Tags(), "Should not change tags")
|
||||
assert.Equal(t, "access_log", processed[0].Name(), "Should not change name")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagConversions(t *testing.T) {
|
||||
tests := []struct {
|
||||
message string
|
||||
converter converter
|
||||
expectedTags map[string]string
|
||||
}{
|
||||
{
|
||||
message: "Should change existing tag",
|
||||
converter: converter{
|
||||
Key: "resp_code",
|
||||
Pattern: "^(\\d)\\d\\d$",
|
||||
Replacement: "${1}xx",
|
||||
},
|
||||
expectedTags: map[string]string{
|
||||
"verb": "GET",
|
||||
"resp_code": "2xx",
|
||||
},
|
||||
},
|
||||
{
|
||||
message: "Should add new tag",
|
||||
converter: converter{
|
||||
Key: "resp_code",
|
||||
Pattern: "^(\\d)\\d\\d$",
|
||||
Replacement: "${1}xx",
|
||||
ResultKey: "resp_code_group",
|
||||
},
|
||||
expectedTags: map[string]string{
|
||||
"verb": "GET",
|
||||
"resp_code": "200",
|
||||
"resp_code_group": "2xx",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
regex := NewRegex()
|
||||
regex.Tags = []converter{
|
||||
test.converter,
|
||||
}
|
||||
|
||||
processed := regex.Apply(newM1())
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"request": "/users/42/",
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedFields, processed[0].Fields(), test.message, "Should not change fields")
|
||||
assert.Equal(t, test.expectedTags, processed[0].Tags(), test.message)
|
||||
assert.Equal(t, "access_log", processed[0].Name(), "Should not change name")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleConversions(t *testing.T) {
|
||||
regex := NewRegex()
|
||||
regex.Tags = []converter{
|
||||
{
|
||||
Key: "resp_code",
|
||||
Pattern: "^(\\d)\\d\\d$",
|
||||
Replacement: "${1}xx",
|
||||
ResultKey: "resp_code_group",
|
||||
},
|
||||
{
|
||||
Key: "resp_code_group",
|
||||
Pattern: "2xx",
|
||||
Replacement: "OK",
|
||||
ResultKey: "resp_code_text",
|
||||
},
|
||||
}
|
||||
regex.Fields = []converter{
|
||||
{
|
||||
Key: "request",
|
||||
Pattern: "^/api(?P<method>/[\\w/]+)\\S*",
|
||||
Replacement: "${method}",
|
||||
ResultKey: "method",
|
||||
},
|
||||
{
|
||||
Key: "request",
|
||||
Pattern: ".*category=(\\w+).*",
|
||||
Replacement: "${1}",
|
||||
ResultKey: "search_category",
|
||||
},
|
||||
}
|
||||
|
||||
processed := regex.Apply(newM2())
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"request": "/api/search/?category=plugins&q=regex&sort=asc",
|
||||
"method": "/search/",
|
||||
"search_category": "plugins",
|
||||
"ignore_number": int64(200),
|
||||
"ignore_bool": true,
|
||||
}
|
||||
expectedTags := map[string]string{
|
||||
"verb": "GET",
|
||||
"resp_code": "200",
|
||||
"resp_code_group": "2xx",
|
||||
"resp_code_text": "OK",
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedFields, processed[0].Fields())
|
||||
assert.Equal(t, expectedTags, processed[0].Tags())
|
||||
}
|
||||
|
||||
func TestNoMatches(t *testing.T) {
|
||||
tests := []struct {
|
||||
message string
|
||||
converter converter
|
||||
expectedFields map[string]interface{}
|
||||
}{
|
||||
{
|
||||
message: "Should not change anything if there is no field with given key",
|
||||
converter: converter{
|
||||
Key: "not_exists",
|
||||
Pattern: "\\.*",
|
||||
Replacement: "x",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"request": "/users/42/",
|
||||
},
|
||||
},
|
||||
{
|
||||
message: "Should not change anything if regex doesn't match",
|
||||
converter: converter{
|
||||
Key: "request",
|
||||
Pattern: "not_match",
|
||||
Replacement: "x",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"request": "/users/42/",
|
||||
},
|
||||
},
|
||||
{
|
||||
message: "Should emit empty string when result_key given but regex doesn't match",
|
||||
converter: converter{
|
||||
Key: "request",
|
||||
Pattern: "not_match",
|
||||
Replacement: "x",
|
||||
ResultKey: "new_field",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"request": "/users/42/",
|
||||
"new_field": "",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
regex := NewRegex()
|
||||
regex.Fields = []converter{
|
||||
test.converter,
|
||||
}
|
||||
|
||||
processed := regex.Apply(newM1())
|
||||
|
||||
assert.Equal(t, test.expectedFields, processed[0].Fields(), test.message)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConversions(b *testing.B) {
|
||||
regex := NewRegex()
|
||||
regex.Tags = []converter{
|
||||
{
|
||||
Key: "resp_code",
|
||||
Pattern: "^(\\d)\\d\\d$",
|
||||
Replacement: "${1}xx",
|
||||
ResultKey: "resp_code_group",
|
||||
},
|
||||
}
|
||||
regex.Fields = []converter{
|
||||
{
|
||||
Key: "request",
|
||||
Pattern: "^/users/\\d+/$",
|
||||
Replacement: "/users/{id}/",
|
||||
},
|
||||
}
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
processed := regex.Apply(newM1())
|
||||
_ = processed
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user