feat(processors.defaults): Add support for specifying default tags (#16717)
Co-authored-by: Pieter Slabbert <pieter.slabbert@ilovezoona.com>
This commit is contained in:
parent
aa68d6175a
commit
9ed15a6194
|
|
@ -1,14 +1,14 @@
|
||||||
# Defaults Processor Plugin
|
# Defaults Processor Plugin
|
||||||
|
|
||||||
The _Defaults_ processor allows you to ensure certain fields will always exist
|
The _Defaults_ processor allows you to ensure certain fields and tags will
|
||||||
with a specified default value on your metric(s).
|
always exist with a specified default value on your metric(s).
|
||||||
|
|
||||||
There are three cases where this processor will insert a configured default
|
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/tag is nil on the incoming metric
|
||||||
1. The field is not nil, but its value is an empty string.
|
1. The field/tag 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 not nil, but its value is a string of one or more empty spaces.
|
||||||
|
|
||||||
Telegraf minimum version: Telegraf 1.15.0
|
Telegraf minimum version: Telegraf 1.15.0
|
||||||
|
|
||||||
|
|
@ -24,11 +24,11 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
```toml @sample.conf
|
```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]]
|
[[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.
|
## 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.
|
## is set on the metric with the specified default.
|
||||||
##
|
##
|
||||||
## A field is considered not set if it is nil on the incoming metric;
|
## 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"
|
field_1 = "bar"
|
||||||
time_idle = 0
|
time_idle = 0
|
||||||
is_error = true
|
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.
|
||||||
|
## <target-tag> = <value>
|
||||||
|
[processors.defaults.tags]
|
||||||
|
tag_1 = "foo"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ var sampleConfig string
|
||||||
// on your Metrics with at least a default value.
|
// on your Metrics with at least a default value.
|
||||||
type Defaults struct {
|
type Defaults struct {
|
||||||
DefaultFieldsSets map[string]interface{} `toml:"fields"`
|
DefaultFieldsSets map[string]interface{} `toml:"fields"`
|
||||||
|
DefaultTagsSets map[string]string `toml:"tags"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Defaults) SampleConfig() string {
|
func (*Defaults) SampleConfig() string {
|
||||||
|
|
@ -37,6 +38,14 @@ func (def *Defaults) Apply(inputMetrics ...telegraf.Metric) []telegraf.Metric {
|
||||||
metric.AddField(defField, defValue)
|
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
|
return inputMetrics
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
func TestTracking(t *testing.T) {
|
||||||
inputRaw := []telegraf.Metric{
|
inputRaw := []telegraf.Metric{
|
||||||
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42, "topic": "telegraf"}, time.Unix(0, 0)),
|
metric.New("foo", map[string]string{}, map[string]interface{}{"value": 42, "topic": "telegraf"}, time.Unix(0, 0)),
|
||||||
|
|
|
||||||
|
|
@ -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]]
|
[[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.
|
## 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.
|
## is set on the metric with the specified default.
|
||||||
##
|
##
|
||||||
## A field is considered not set if it is nil on the incoming metric;
|
## A field is considered not set if it is nil on the incoming metric;
|
||||||
|
|
@ -13,3 +13,9 @@
|
||||||
field_1 = "bar"
|
field_1 = "bar"
|
||||||
time_idle = 0
|
time_idle = 0
|
||||||
is_error = true
|
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.
|
||||||
|
## <target-tag> = <value>
|
||||||
|
[processors.defaults.tags]
|
||||||
|
tag_1 = "foo"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue