diff --git a/plugins/processors/regex/README.md b/plugins/processors/regex/README.md index 3fb3e5293..95f8633cb 100644 --- a/plugins/processors/regex/README.md +++ b/plugins/processors/regex/README.md @@ -15,7 +15,7 @@ For metrics transforms, `key` denotes the element that should be transformed. Fu # Tag and field conversions defined in a separate sub-tables [[processors.regex.tags]] - ## Tag to change + ## Tag to change, "*" will change every tag key = "resp_code" ## Regular expression to match on a tag value pattern = "^(\\d)\\d\\d$" diff --git a/plugins/processors/regex/regex.go b/plugins/processors/regex/regex.go index c504f60d3..cc811c1f6 100644 --- a/plugins/processors/regex/regex.go +++ b/plugins/processors/regex/regex.go @@ -97,14 +97,17 @@ func (r *Regex) Init() error { func (r *Regex) Apply(in ...telegraf.Metric) []telegraf.Metric { for _, metric := range in { for _, converter := range r.Tags { - if value, ok := metric.GetTag(converter.Key); ok { - if key, newValue := r.convert(converter, value); newValue != "" { - if converter.Append { - if v, ok := metric.GetTag(key); ok { - newValue = v + newValue - } + if converter.Key == "*" { + for _, tag := range metric.TagList() { + regex := r.regexCache[converter.Pattern] + if regex.MatchString(tag.Value) { + newValue := regex.ReplaceAllString(tag.Value, converter.Replacement) + updateTag(converter, metric, tag.Key, newValue) } - metric.AddTag(key, newValue) + } + } else if value, ok := metric.GetTag(converter.Key); ok { + if key, newValue := r.convert(converter, value); newValue != "" { + updateTag(converter, metric, key, newValue) } } } @@ -212,6 +215,15 @@ func (r *Regex) convert(c converter, src string) (key string, value string) { return c.Key, value } +func updateTag(converter converter, metric telegraf.Metric, key string, newValue string) { + if converter.Append { + if v, ok := metric.GetTag(key); ok { + newValue = v + newValue + } + } + metric.AddTag(key, newValue) +} + func init() { processors.Add("regex", func() telegraf.Processor { return &Regex{} }) } diff --git a/plugins/processors/regex/regex_test.go b/plugins/processors/regex/regex_test.go index 8baa0d79a..56d6cb0e2 100644 --- a/plugins/processors/regex/regex_test.go +++ b/plugins/processors/regex/regex_test.go @@ -1,6 +1,8 @@ package regex import ( + "github.com/influxdata/telegraf/metric" + "github.com/stretchr/testify/assert" "testing" "time" @@ -40,6 +42,21 @@ func newM2() telegraf.Metric { ) } +func newUUIDTags() telegraf.Metric { + m1 := metric.New("access_log", + map[string]string{ + "compound": "other-18cb0b46-73b8-4084-9fc4-5105f32a8a68", + "simple": "d60be57c-2f43-4e4f-a68a-4ca8204bae41", + "control": "not_uuid", + }, + map[string]interface{}{ + "request": "/users/42/", + }, + time.Now(), + ) + return m1 +} + func TestFieldConversions(t *testing.T) { tests := []struct { message string @@ -828,3 +845,43 @@ func BenchmarkConversions(b *testing.B) { _ = processed } } + +func TestAnyTagConversion(t *testing.T) { + tests := []struct { + message string + converter converter + expectedTags map[string]string + }{ + { + message: "Should change existing tag", + converter: converter{ + Key: "*", + Pattern: "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + Replacement: "{UUID}", + }, + expectedTags: map[string]string{ + "compound": "other-{UUID}", + "simple": "{UUID}", + "control": "not_uuid", + }, + }, + } + + for _, test := range tests { + regex := Regex{ + Tags: []converter{test.converter}, + Log: testutil.Logger{}, + } + require.NoError(t, regex.Init()) + + processed := regex.Apply(newUUIDTags()) + + 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") + } +}