diff --git a/config/config.go b/config/config.go index 4233234d0..529fbbd67 100644 --- a/config/config.go +++ b/config/config.go @@ -263,6 +263,10 @@ type AgentConfig struct { // Flag to always keep tags explicitly defined in the plugin itself and // ensure those tags always pass filtering. AlwaysIncludeLocalTags bool `toml:"always_include_local_tags"` + + // Flag to always keep tags explicitly defined in the global tags section + // and ensure those tags always pass filtering. + AlwaysIncludeGlobalTags bool `toml:"always_include_global_tags"` } // InputNames returns a list of strings of the configured inputs. @@ -1459,8 +1463,9 @@ func (c *Config) buildFilter(tbl *ast.Table) (models.Filter, error) { // models.InputConfig to be inserted into models.RunningInput func (c *Config) buildInput(name string, tbl *ast.Table) (*models.InputConfig, error) { cp := &models.InputConfig{ - Name: name, - AlwaysIncludeLocalTags: c.Agent.AlwaysIncludeLocalTags, + Name: name, + AlwaysIncludeLocalTags: c.Agent.AlwaysIncludeLocalTags, + AlwaysIncludeGlobalTags: c.Agent.AlwaysIncludeGlobalTags, } c.getFieldDuration(tbl, "interval", &cp.Interval) c.getFieldDuration(tbl, "precision", &cp.Precision) diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index e92f0b325..c849392d0 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -326,6 +326,11 @@ The agent table configures Telegraf and the defaults used across all plugins. via `taginclude` or `tagexclude`. This removes the need to specify local tags twice. +- **always_include_global_tags**: + Ensure tags explicitly defined in the `global_tags` section will *always* pass + tag-filtering via `taginclude` or `tagexclude`. This removes the need to + specify those tags twice. + ## Plugins Telegraf plugins are divided into 4 types: [inputs][], [outputs][], diff --git a/models/running_input.go b/models/running_input.go index 2f6ea8eae..527a22363 100644 --- a/models/running_input.go +++ b/models/running_input.go @@ -71,12 +71,13 @@ type InputConfig struct { CollectionOffset time.Duration Precision time.Duration - NameOverride string - MeasurementPrefix string - MeasurementSuffix string - Tags map[string]string - Filter Filter - AlwaysIncludeLocalTags bool + NameOverride string + MeasurementPrefix string + MeasurementSuffix string + Tags map[string]string + Filter Filter + AlwaysIncludeLocalTags bool + AlwaysIncludeGlobalTags bool } func (r *RunningInput) metricFiltered(metric telegraf.Metric) { @@ -113,17 +114,12 @@ func (r *RunningInput) MakeMetric(metric telegraf.Metric) telegraf.Metric { return nil } - tags := r.Config.Tags - if r.Config.AlwaysIncludeLocalTags { - tags = nil - } - - m := makemetric( + makemetric( metric, r.Config.NameOverride, r.Config.MeasurementPrefix, r.Config.MeasurementSuffix, - tags, + r.Config.Tags, r.defaultTags) r.Config.Filter.Modify(metric) @@ -132,18 +128,20 @@ func (r *RunningInput) MakeMetric(metric telegraf.Metric) telegraf.Metric { return nil } - if r.Config.AlwaysIncludeLocalTags { - // Apply plugin tags after filtering - for k, v := range r.Config.Tags { - if _, ok := metric.GetTag(k); !ok { - metric.AddTag(k, v) - } + if r.Config.AlwaysIncludeLocalTags || r.Config.AlwaysIncludeGlobalTags { + var local, global map[string]string + if r.Config.AlwaysIncludeLocalTags { + local = r.Config.Tags } + if r.Config.AlwaysIncludeGlobalTags { + global = r.defaultTags + } + makemetric(metric, "", "", "", local, global) } r.MetricsGathered.Incr(1) GlobalMetricsGathered.Incr(1) - return m + return metric } func (r *RunningInput) Gather(acc telegraf.Accumulator) error { diff --git a/models/running_input_test.go b/models/running_input_test.go index 56d961e17..eff0425d1 100644 --- a/models/running_input_test.go +++ b/models/running_input_test.go @@ -55,8 +55,8 @@ func TestMakeMetricNoFields(t *testing.T) { map[string]interface{}{}, now, telegraf.Untyped) - m = ri.MakeMetric(m) - assert.Nil(t, m) + actual := ri.MakeMetric(m) + require.Nil(t, actual) } // nil fields should get dropped @@ -74,7 +74,7 @@ func TestMakeMetricNilFields(t *testing.T) { }, now, telegraf.Untyped) - m = ri.MakeMetric(m) + actual := ri.MakeMetric(m) expected := metric.New("RITest", map[string]string{}, @@ -84,7 +84,7 @@ func TestMakeMetricNilFields(t *testing.T) { now, ) - require.Equal(t, expected, m) + require.Equal(t, expected, actual) } func TestMakeMetricWithPluginTags(t *testing.T) { @@ -103,7 +103,7 @@ func TestMakeMetricWithPluginTags(t *testing.T) { }, now, telegraf.Untyped) - m = ri.MakeMetric(m) + actual := ri.MakeMetric(m) expected := metric.New("RITest", map[string]string{ @@ -114,7 +114,7 @@ func TestMakeMetricWithPluginTags(t *testing.T) { }, now, ) - require.Equal(t, expected, m) + require.Equal(t, expected, actual) } func TestMakeMetricFilteredOut(t *testing.T) { @@ -136,8 +136,8 @@ func TestMakeMetricFilteredOut(t *testing.T) { }, now, telegraf.Untyped) - m = ri.MakeMetric(m) - assert.Nil(t, m) + actual := ri.MakeMetric(m) + require.Nil(t, actual) } func TestMakeMetricWithDaemonTags(t *testing.T) { @@ -156,7 +156,7 @@ func TestMakeMetricWithDaemonTags(t *testing.T) { }, now, telegraf.Untyped) - m = ri.MakeMetric(m) + actual := ri.MakeMetric(m) expected := metric.New("RITest", map[string]string{ "foo": "bar", @@ -166,7 +166,7 @@ func TestMakeMetricWithDaemonTags(t *testing.T) { }, now, ) - require.Equal(t, expected, m) + require.Equal(t, expected, actual) } func TestMakeMetricNameOverride(t *testing.T) { @@ -183,7 +183,7 @@ func TestMakeMetricNameOverride(t *testing.T) { }, now, telegraf.Untyped) - m = ri.MakeMetric(m) + actual := ri.MakeMetric(m) expected := metric.New("foobar", nil, map[string]interface{}{ @@ -191,7 +191,7 @@ func TestMakeMetricNameOverride(t *testing.T) { }, now, ) - require.Equal(t, expected, m) + require.Equal(t, expected, actual) } func TestMakeMetricNamePrefix(t *testing.T) { @@ -208,7 +208,7 @@ func TestMakeMetricNamePrefix(t *testing.T) { }, now, telegraf.Untyped) - m = ri.MakeMetric(m) + actual := ri.MakeMetric(m) expected := metric.New("foobar_RITest", nil, map[string]interface{}{ @@ -216,7 +216,7 @@ func TestMakeMetricNamePrefix(t *testing.T) { }, now, ) - require.Equal(t, expected, m) + require.Equal(t, expected, actual) } func TestMakeMetricNameSuffix(t *testing.T) { @@ -233,7 +233,7 @@ func TestMakeMetricNameSuffix(t *testing.T) { }, now, telegraf.Untyped) - m = ri.MakeMetric(m) + actual := ri.MakeMetric(m) expected := metric.New("RITest_foobar", nil, map[string]interface{}{ @@ -241,7 +241,7 @@ func TestMakeMetricNameSuffix(t *testing.T) { }, now, ) - require.Equal(t, expected, m) + require.Equal(t, expected, actual) } func TestMetricErrorCounters(t *testing.T) { @@ -283,8 +283,8 @@ func TestMakeMetricWithAlwaysKeepingPluginTagsDisabled(t *testing.T) { Filter: Filter{ TagInclude: []string{"b"}, }, - AlwaysIncludeLocalTags: false, }) + ri.SetDefaultTags(map[string]string{"logic": "rulez"}) require.NoError(t, ri.Config.Filter.Compile()) m := testutil.MustMetric("RITest", @@ -296,7 +296,7 @@ func TestMakeMetricWithAlwaysKeepingPluginTagsDisabled(t *testing.T) { }, now, telegraf.Untyped) - m = ri.MakeMetric(m) + actual := ri.MakeMetric(m) expected := metric.New("RITest", map[string]string{ @@ -307,7 +307,85 @@ func TestMakeMetricWithAlwaysKeepingPluginTagsDisabled(t *testing.T) { }, now, ) - require.Equal(t, expected, m) + require.Equal(t, expected, actual) +} + +func TestMakeMetricWithAlwaysKeepingLocalPluginTagsEnabled(t *testing.T) { + now := time.Now() + ri := NewRunningInput(&testInput{}, &InputConfig{ + Name: "TestRunningInput", + Tags: map[string]string{ + "foo": "bar", + }, + Filter: Filter{ + TagInclude: []string{"b"}, + }, + AlwaysIncludeLocalTags: true, + }) + ri.SetDefaultTags(map[string]string{"logic": "rulez"}) + require.NoError(t, ri.Config.Filter.Compile()) + + m := testutil.MustMetric("RITest", + map[string]string{ + "b": "test", + }, + map[string]interface{}{ + "value": int64(101), + }, + now, + telegraf.Untyped) + actual := ri.MakeMetric(m) + + expected := metric.New("RITest", + map[string]string{ + "b": "test", + "foo": "bar", + }, + map[string]interface{}{ + "value": 101, + }, + now, + ) + require.Equal(t, expected, actual) +} + +func TestMakeMetricWithAlwaysKeepingGlobalPluginTagsEnabled(t *testing.T) { + now := time.Now() + ri := NewRunningInput(&testInput{}, &InputConfig{ + Name: "TestRunningInput", + Tags: map[string]string{ + "foo": "bar", + }, + Filter: Filter{ + TagInclude: []string{"b"}, + }, + AlwaysIncludeGlobalTags: true, + }) + ri.SetDefaultTags(map[string]string{"logic": "rulez"}) + require.NoError(t, ri.Config.Filter.Compile()) + + m := testutil.MustMetric("RITest", + map[string]string{ + "b": "test", + }, + map[string]interface{}{ + "value": int64(101), + }, + now, + telegraf.Untyped) + actual := ri.MakeMetric(m) + + expected := metric.New("RITest", + map[string]string{ + "b": "test", + "logic": "rulez", + }, + map[string]interface{}{ + "value": 101, + }, + now, + ) + require.Equal(t, expected, actual) } func TestMakeMetricWithAlwaysKeepingPluginTagsEnabled(t *testing.T) { @@ -320,8 +398,10 @@ func TestMakeMetricWithAlwaysKeepingPluginTagsEnabled(t *testing.T) { Filter: Filter{ TagInclude: []string{"b"}, }, - AlwaysIncludeLocalTags: true, + AlwaysIncludeLocalTags: true, + AlwaysIncludeGlobalTags: true, }) + ri.SetDefaultTags(map[string]string{"logic": "rulez"}) require.NoError(t, ri.Config.Filter.Compile()) m := testutil.MustMetric("RITest", @@ -333,19 +413,20 @@ func TestMakeMetricWithAlwaysKeepingPluginTagsEnabled(t *testing.T) { }, now, telegraf.Untyped) - m = ri.MakeMetric(m) + actual := ri.MakeMetric(m) expected := metric.New("RITest", map[string]string{ - "b": "test", - "foo": "bar", + "b": "test", + "foo": "bar", + "logic": "rulez", }, map[string]interface{}{ "value": 101, }, now, ) - require.Equal(t, expected, m) + require.Equal(t, expected, actual) } type testInput struct{}