feat(agent): Add option to avoid filtering of explicit plugin tags (#13364)

This commit is contained in:
Sven Rebhan 2023-05-31 19:06:50 +02:00 committed by GitHub
parent 5a8ccbde6f
commit 0a491a7bf3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 112 additions and 10 deletions

View File

@ -252,6 +252,10 @@ type AgentConfig struct {
// stateful plugins on termination of Telegraf. If the file exists on start, // stateful plugins on termination of Telegraf. If the file exists on start,
// the state in the file will be restored for the plugins. // the state in the file will be restored for the plugins.
Statefile string `toml:"statefile"` Statefile string `toml:"statefile"`
// 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"`
} }
// InputNames returns a list of strings of the configured inputs. // InputNames returns a list of strings of the configured inputs.
@ -1428,7 +1432,10 @@ func (c *Config) buildFilter(tbl *ast.Table) (models.Filter, error) {
// builds the filter and returns a // builds the filter and returns a
// models.InputConfig to be inserted into models.RunningInput // models.InputConfig to be inserted into models.RunningInput
func (c *Config) buildInput(name string, tbl *ast.Table) (*models.InputConfig, error) { func (c *Config) buildInput(name string, tbl *ast.Table) (*models.InputConfig, error) {
cp := &models.InputConfig{Name: name} cp := &models.InputConfig{
Name: name,
AlwaysIncludeLocalTags: c.Agent.AlwaysIncludeLocalTags,
}
c.getFieldDuration(tbl, "interval", &cp.Interval) c.getFieldDuration(tbl, "interval", &cp.Interval)
c.getFieldDuration(tbl, "precision", &cp.Precision) c.getFieldDuration(tbl, "precision", &cp.Precision)
c.getFieldDuration(tbl, "collection_jitter", &cp.CollectionJitter) c.getFieldDuration(tbl, "collection_jitter", &cp.CollectionJitter)
@ -1523,7 +1530,7 @@ func (c *Config) buildOutput(name string, tbl *ast.Table) (*models.OutputConfig,
func (c *Config) missingTomlField(_ reflect.Type, key string) error { func (c *Config) missingTomlField(_ reflect.Type, key string) error {
switch key { switch key {
// General options to ignore // General options to ignore
case "alias", case "alias", "always_include_local_tags",
"collection_jitter", "collection_offset", "collection_jitter", "collection_offset",
"data_format", "delay", "drop", "drop_original", "data_format", "delay", "drop", "drop_original",
"fielddrop", "fieldpass", "flush_interval", "flush_jitter", "fielddrop", "fieldpass", "flush_interval", "flush_jitter",

View File

@ -321,6 +321,11 @@ The agent table configures Telegraf and the defaults used across all plugins.
stateful plugins on termination of Telegraf. If the file exists on start, stateful plugins on termination of Telegraf. If the file exists on start,
the state in the file will be restored for the plugins. the state in the file will be restored for the plugins.
- **always_include_local_tags**:
Ensure tags explicitly defined in a plugin will *always* pass tag-filtering
via `taginclude` or `tagexclude`. This removes the need to specify local tags
twice.
## Plugins ## Plugins
Telegraf plugins are divided into 4 types: [inputs][], [outputs][], Telegraf plugins are divided into 4 types: [inputs][], [outputs][],
@ -402,7 +407,7 @@ Use the name_override parameter to emit measurements with the name `foobar`:
Emit measurements with two additional tags: `tag1=foo` and `tag2=bar` Emit measurements with two additional tags: `tag1=foo` and `tag2=bar`
> **NOTE**: With TOML, order matters. Parameters belong to the last defined > **NOTE**: With TOML, order matters. Parameters belong to the last defined
> table header, place `[inputs.cpu.tags]` table at the _end_ of the plugin > table header, place `[inputs.cpu.tags]` table at the *end* of the plugin
> definition. > definition.
```toml ```toml
@ -638,7 +643,7 @@ for time-based filtering. An introduction to the CEL language can be found
are provided in the [language definition][CEL lang] as well as in the are provided in the [language definition][CEL lang] as well as in the
[extension documentation][CEL ext]. [extension documentation][CEL ext].
> NOTE: As CEL is an _interpreted_ languguage, this type of filtering is much > NOTE: As CEL is an *interpreted* languguage, this type of filtering is much
> slower compared to `namepass`/`namedrop` and friends. So consider to use the > slower compared to `namepass`/`namedrop` and friends. So consider to use the
> more restricted filter options where possible in case of high-throughput > more restricted filter options where possible in case of high-throughput
> scenarios. > scenarios.

View File

@ -64,11 +64,12 @@ type InputConfig struct {
CollectionOffset time.Duration CollectionOffset time.Duration
Precision time.Duration Precision time.Duration
NameOverride string NameOverride string
MeasurementPrefix string MeasurementPrefix string
MeasurementSuffix string MeasurementSuffix string
Tags map[string]string Tags map[string]string
Filter Filter Filter Filter
AlwaysIncludeLocalTags bool
} }
func (r *RunningInput) metricFiltered(metric telegraf.Metric) { func (r *RunningInput) metricFiltered(metric telegraf.Metric) {
@ -105,12 +106,17 @@ func (r *RunningInput) MakeMetric(metric telegraf.Metric) telegraf.Metric {
return nil return nil
} }
tags := r.Config.Tags
if r.Config.AlwaysIncludeLocalTags {
tags = nil
}
m := makemetric( m := makemetric(
metric, metric,
r.Config.NameOverride, r.Config.NameOverride,
r.Config.MeasurementPrefix, r.Config.MeasurementPrefix,
r.Config.MeasurementSuffix, r.Config.MeasurementSuffix,
r.Config.Tags, tags,
r.defaultTags) r.defaultTags)
r.Config.Filter.Modify(metric) r.Config.Filter.Modify(metric)
@ -119,6 +125,15 @@ func (r *RunningInput) MakeMetric(metric telegraf.Metric) telegraf.Metric {
return nil 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)
}
}
}
r.MetricsGathered.Incr(1) r.MetricsGathered.Incr(1)
GlobalMetricsGathered.Incr(1) GlobalMetricsGathered.Incr(1)
return m return m

View File

@ -273,6 +273,81 @@ func TestMetricErrorCounters(t *testing.T) {
require.GreaterOrEqual(t, int64(1), GlobalGatherErrors.Get()) require.GreaterOrEqual(t, int64(1), GlobalGatherErrors.Get())
} }
func TestMakeMetricWithAlwaysKeepingPluginTagsDisabled(t *testing.T) {
now := time.Now()
ri := NewRunningInput(&testInput{}, &InputConfig{
Name: "TestRunningInput",
Tags: map[string]string{
"foo": "bar",
},
Filter: Filter{
TagInclude: []string{"b"},
},
AlwaysIncludeLocalTags: false,
})
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)
m = ri.MakeMetric(m)
expected := metric.New("RITest",
map[string]string{
"b": "test",
},
map[string]interface{}{
"value": 101,
},
now,
)
require.Equal(t, expected, m)
}
func TestMakeMetricWithAlwaysKeepingPluginTagsEnabled(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,
})
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)
m = ri.MakeMetric(m)
expected := metric.New("RITest",
map[string]string{
"b": "test",
"foo": "bar",
},
map[string]interface{}{
"value": 101,
},
now,
)
require.Equal(t, expected, m)
}
type testInput struct{} type testInput struct{}
func (t *testInput) Description() string { return "" } func (t *testInput) Description() string { return "" }