diff --git a/plugins/processors/defaults/README.md b/plugins/processors/defaults/README.md index 0fc1763a8..1e541b571 100644 --- a/plugins/processors/defaults/README.md +++ b/plugins/processors/defaults/README.md @@ -1,14 +1,14 @@ # Defaults Processor Plugin -The _Defaults_ processor allows you to ensure certain fields will always exist -with a specified default value on your metric(s). +The _Defaults_ processor allows you to ensure certain fields and tags will +always exist with a specified default value on your metric(s). There are three cases where this processor will insert a configured default -field. +field or tag. -1. The field is nil on the incoming metric -1. The field is not nil, but its value is an empty string. -1. The field is not nil, but its value is a string of one or more empty spaces. +1. The field/tag is nil on the incoming metric +1. The field/tag is not nil, but its value is an empty string. +1. The field/tag is not nil, but its value is a string of one or more empty spaces. Telegraf minimum version: Telegraf 1.15.0 @@ -24,11 +24,11 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. ## Configuration ```toml @sample.conf -## Set default fields on your metric(s) when they are nil or empty +## Set default fields and tags on your metric(s) when they are nil or empty [[processors.defaults]] - ## Ensures a set of fields always exists on your metric(s) with their + ## Ensures a set of fields or tags always exists on your metric(s) with their ## respective default value. - ## For any given field pair (key = default), if it's not set, a field + ## For any given field/tag pair (key = default), if it's not set, a field/tag ## is set on the metric with the specified default. ## ## A field is considered not set if it is nil on the incoming metric; @@ -39,6 +39,12 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. field_1 = "bar" time_idle = 0 is_error = true + ## A tag is considered not set if it is nil on the incoming metric; + ## or it is not nil but it is empty string or a string of one or + ## more spaces. + ## = + [processors.defaults.tags] + tag_1 = "foo" ``` ## Example diff --git a/plugins/processors/defaults/defaults.go b/plugins/processors/defaults/defaults.go index 1c16d1c13..89417f689 100644 --- a/plugins/processors/defaults/defaults.go +++ b/plugins/processors/defaults/defaults.go @@ -16,6 +16,7 @@ var sampleConfig string // on your Metrics with at least a default value. type Defaults struct { DefaultFieldsSets map[string]interface{} `toml:"fields"` + DefaultTagsSets map[string]string `toml:"tags"` } func (*Defaults) SampleConfig() string { @@ -37,6 +38,14 @@ func (def *Defaults) Apply(inputMetrics ...telegraf.Metric) []telegraf.Metric { metric.AddField(defField, defValue) } } + for defTag, defValue := range def.DefaultTagsSets { + if maybeCurrent, isSet := metric.GetTag(defTag); !isSet { + metric.AddTag(defTag, defValue) + } else if trimmed := strings.TrimSpace(maybeCurrent); trimmed == "" { + metric.RemoveTag(defTag) + metric.AddTag(defTag, defValue) + } + } } return inputMetrics } diff --git a/plugins/processors/defaults/defaults_test.go b/plugins/processors/defaults/defaults_test.go index 05bf470f1..7ef81b165 100644 --- a/plugins/processors/defaults/defaults_test.go +++ b/plugins/processors/defaults/defaults_test.go @@ -133,6 +133,124 @@ func TestDefaults(t *testing.T) { } } +func TestTagDefaults(t *testing.T) { + scenarios := []struct { + name string + defaults *Defaults + input telegraf.Metric + expected []telegraf.Metric + }{ + { + name: "Test that no values are changed since they are not nil or empty", + defaults: &Defaults{ + DefaultTagsSets: map[string]string{ + "wind_feel": "very chill", + }, + }, + input: testutil.MustMetric( + "CPU metrics", + map[string]string{ + "wind_feel": "a dragon's breath", + }, + map[string]interface{}{ + "usage": 45, + "is_dead": false, + }, + time.Unix(0, 0), + ), + expected: []telegraf.Metric{ + testutil.MustMetric( + "CPU metrics", + map[string]string{ + "wind_feel": "a dragon's breath", + }, + map[string]interface{}{ + "usage": 45, + "is_dead": false, + }, + time.Unix(0, 0), + ), + }, + }, + { + name: "Tests that the missing tags are set on the metric", + defaults: &Defaults{ + DefaultTagsSets: map[string]string{ + "wind_feel": "Unknown", + }, + }, + input: testutil.MustMetric( + "CPU metrics", + map[string]string{}, + map[string]interface{}{ + "usage": 45, + "temperature": 64, + }, + time.Unix(0, 0), + ), + expected: []telegraf.Metric{ + testutil.MustMetric( + "CPU metrics", + map[string]string{ + "wind_feel": "Unknown", + }, + map[string]interface{}{ + "usage": 45, + "temperature": 64, + }, + time.Unix(0, 0), + ), + }, + }, + { + name: "Tests that set but empty tags are replaced by specified defaults", + defaults: &Defaults{ + DefaultTagsSets: map[string]string{ + "wind_feel": "Unknown", + "fan_loudness": "Inaudible", + "boost_enabled": "false", + }, + }, + input: testutil.MustMetric( + "CPU metrics", + map[string]string{ + "wind_feel": " ", + "fan_loudness": " ", + "boost_enabled": "", + }, + map[string]interface{}{ + "max_clock_gz": 0, + }, + time.Unix(0, 0), + ), + expected: []telegraf.Metric{ + testutil.MustMetric( + "CPU metrics", + map[string]string{ + "wind_feel": "Unknown", + "fan_loudness": "Inaudible", + "boost_enabled": "false", + }, + map[string]interface{}{ + "max_clock_gz": 0, + }, + time.Unix(0, 0), + ), + }, + }, + } + + for _, scenario := range scenarios { + t.Run(scenario.name, func(t *testing.T) { + defaults := scenario.defaults + + resultMetrics := defaults.Apply(scenario.input) + require.Len(t, resultMetrics, 1) + testutil.RequireMetricsEqual(t, scenario.expected, resultMetrics) + }) + } +} + func TestTracking(t *testing.T) { inputRaw := []telegraf.Metric{ metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42, "topic": "telegraf"}, time.Unix(0, 0)), diff --git a/plugins/processors/defaults/sample.conf b/plugins/processors/defaults/sample.conf index eb25617a3..6eb2d1774 100644 --- a/plugins/processors/defaults/sample.conf +++ b/plugins/processors/defaults/sample.conf @@ -1,8 +1,8 @@ -## Set default fields on your metric(s) when they are nil or empty +## Set default fields and tags on your metric(s) when they are nil or empty [[processors.defaults]] - ## Ensures a set of fields always exists on your metric(s) with their + ## Ensures a set of fields or tags always exists on your metric(s) with their ## respective default value. - ## For any given field pair (key = default), if it's not set, a field + ## For any given field/tag pair (key = default), if it's not set, a field/tag ## is set on the metric with the specified default. ## ## A field is considered not set if it is nil on the incoming metric; @@ -13,3 +13,9 @@ field_1 = "bar" time_idle = 0 is_error = true + ## A tag is considered not set if it is nil on the incoming metric; + ## or it is not nil but it is empty string or a string of one or + ## more spaces. + ## = + [processors.defaults.tags] + tag_1 = "foo"