feat(processors.filter): Convert noop processor to filter processor (#14330)

This commit is contained in:
Sven Rebhan 2023-11-27 20:19:10 +01:00 committed by GitHub
parent 7b5393c9e5
commit 1c2c03d778
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 939 additions and 189 deletions

View File

@ -0,0 +1,5 @@
//go:build !custom || processors || processors.filter
package all
import _ "github.com/influxdata/telegraf/plugins/processors/filter" // register plugin

View File

@ -1,5 +0,0 @@
//go:build !custom || processors || processors.noop
package all
import _ "github.com/influxdata/telegraf/plugins/processors/noop" // register plugin

View File

@ -0,0 +1,83 @@
# Filter Processor Plugin
The filter processor plugin allows to specify a set of rules for metrics
with the ability to _keep_ or _drop_ those metrics. It does _not_ change the
metric. As such a user might want to apply this processor to remove metrics
from the processing/output stream.
__NOTE:__ The filtering is _not_ output specific, but will apply to the metrics
processed by this processor.
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
In addition to the plugin-specific configuration settings, plugins support
additional global and plugin configuration settings. These settings are used to
modify metrics, tags, and field or create aliases and configure ordering, etc.
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
## Configuration
```toml @sample.conf
# Filter metrics by the given criteria
[[processors.filter]]
## Default action if no rule applies
# default = "pass"
## Rules to apply on the incoming metrics (multiple rules are possible)
## The rules are evaluated in order and the first matching rule is applied.
## In case no rule matches the "default" is applied.
## All filter criteria in a rule must apply for the rule to match the metric
## i.e. the criteria are combined by a logical AND. If a criterion is
## omitted it is NOT applied at all and ignored.
[[processors.filter.rule]]
## List of metric names to match including glob expressions
# name = []
## List of tag key/values pairs to match including glob expressions
## ALL given tags keys must exist and at least one value must match
## for the metric to match the rule.
# tags = {}
## List of field keys to match including glob expressions
## At least one field must exist for the metric to match the rule.
# fields = []
## Action to apply for this rule
## "pass" will keep the metric and pass it on, while "drop" will remove
## the metric
# action = "drop"
```
## Examples
Consider a use-case where you collected a bunch of metrics
```text
machine,source="machine1",status="OK" operating_hours=37i,temperature=23.1
machine,source="machine2",status="warning" operating_hours=1433i,temperature=48.9,message="too hot"
machine,source="machine3",status="OK" operating_hours=811i,temperature=29.5
machine,source="machine4",status="failure" operating_hours=1009i,temperature=67.3,message="temperature alert"
```
but only want to keep the ones indicating a `status` of `failure` or `warning`:
```toml
[[processors.filter]]
namepass = ["machine"]
default = "drop"
[[processors.filter.rule]]
tags = {"status" = ["warning", "failure"]}
action = "pass"
```
Alternatively, you can "black-list" the `OK` value via
```toml
[[processors.filter]]
namepass = ["machine"]
[[processors.filter.rule]]
tags = {"status" = "OK"}
```

View File

@ -0,0 +1,75 @@
//go:generate ../../../tools/readme_config_includer/generator
package filter
import (
_ "embed"
"fmt"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/processors"
)
//go:embed sample.conf
var sampleConfig string
type Filter struct {
Rules []rule `toml:"rule"`
DefaultAction string `toml:"default"`
Log telegraf.Logger `toml:"-"`
defaultPass bool
}
func (*Filter) SampleConfig() string {
return sampleConfig
}
func (f *Filter) Init() error {
// Check the default-action setting
switch f.DefaultAction {
case "", "pass":
f.defaultPass = true
case "drop":
// Do nothing, those options are valid
if len(f.Rules) == 0 {
f.Log.Warn("dropping all metrics as no rule is provided")
}
default:
return fmt.Errorf("invalid default action %q", f.DefaultAction)
}
// Check and initialize rules
for i := range f.Rules {
if err := f.Rules[i].init(); err != nil {
return fmt.Errorf("initialization of rule %d failed: %w", i+1, err)
}
}
return nil
}
func (f *Filter) Apply(in ...telegraf.Metric) []telegraf.Metric {
out := make([]telegraf.Metric, 0, len(in))
for _, m := range in {
if f.applyRules(m) {
out = append(out, m)
} else {
m.Drop()
}
}
return out
}
func (f *Filter) applyRules(m telegraf.Metric) bool {
for _, r := range f.Rules {
if pass, applies := r.apply(m); applies {
return pass
}
}
return f.defaultPass
}
func init() {
processors.Add("Filter", func() telegraf.Processor {
return &Filter{}
})
}

View File

@ -0,0 +1,661 @@
package filter
import (
"testing"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
"github.com/influxdata/telegraf/testutil"
"github.com/stretchr/testify/require"
)
var testmetrics = []telegraf.Metric{
metric.New(
"packing",
map[string]string{
"source": "machine A",
"location": "main building",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 37,
"temperature": 23.1,
},
time.Unix(0, 0),
),
metric.New(
"foundry",
map[string]string{
"source": "machine B",
"location": "factory X",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 1337,
"temperature": 19.9,
"pieces": 96878,
},
time.Unix(0, 0),
),
metric.New(
"welding",
map[string]string{
"source": "machine C",
"location": "factory X",
"status": "failure",
},
map[string]interface{}{
"operating_hours": 1009,
"temperature": 67.3,
"message": "temperature alert",
},
time.Unix(0, 0),
),
metric.New(
"welding",
map[string]string{
"source": "machine D",
"location": "factory Y",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 825,
"temperature": 31.2,
},
time.Unix(0, 0),
),
}
func TestNoRules(t *testing.T) {
logger := &testutil.CaptureLogger{}
plugin := &Filter{
DefaultAction: "drop",
Log: logger,
}
require.NoError(t, plugin.Init())
warnings := logger.Warnings()
require.Len(t, warnings, 1)
require.Contains(t, warnings[0], "dropping all metrics")
}
func TestInvalidDefaultAction(t *testing.T) {
plugin := &Filter{
Rules: []rule{{Name: []string{"foo"}}},
DefaultAction: "foo",
}
require.ErrorContains(t, plugin.Init(), "invalid default action")
}
func TestNoMetric(t *testing.T) {
plugin := &Filter{
Rules: []rule{{Name: []string{"*"}}},
}
require.NoError(t, plugin.Init())
input := []telegraf.Metric{}
require.Empty(t, plugin.Apply(input...))
}
func TestDropAll(t *testing.T) {
plugin := &Filter{
Rules: []rule{{Name: []string{"*"}}},
}
require.NoError(t, plugin.Init())
require.Empty(t, plugin.Apply(testmetrics...))
}
func TestDropDefault(t *testing.T) {
plugin := &Filter{
Rules: []rule{{Name: []string{"foo"}, Action: "pass"}},
DefaultAction: "drop",
}
require.NoError(t, plugin.Init())
require.Empty(t, plugin.Apply(testmetrics...))
}
func TestPassAll(t *testing.T) {
plugin := &Filter{
Rules: []rule{{Name: []string{"*"}, Action: "pass"}},
DefaultAction: "drop",
}
require.NoError(t, plugin.Init())
expected := testmetrics
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestPassDefault(t *testing.T) {
plugin := &Filter{
Rules: []rule{{Name: []string{"foo"}, Action: "drop"}},
}
require.NoError(t, plugin.Init())
expected := testmetrics
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestNamePass(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Name: []string{"welding"},
Action: "pass",
},
},
DefaultAction: "drop",
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"welding",
map[string]string{
"source": "machine C",
"location": "factory X",
"status": "failure",
},
map[string]interface{}{
"operating_hours": 1009,
"temperature": 67.3,
"message": "temperature alert",
},
time.Unix(0, 0),
),
metric.New(
"welding",
map[string]string{
"source": "machine D",
"location": "factory Y",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 825,
"temperature": 31.2,
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestNameDrop(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Name: []string{"welding"},
Action: "drop",
},
},
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"packing",
map[string]string{
"source": "machine A",
"location": "main building",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 37,
"temperature": 23.1,
},
time.Unix(0, 0),
),
metric.New(
"foundry",
map[string]string{
"source": "machine B",
"location": "factory X",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 1337,
"temperature": 19.9,
"pieces": 96878,
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestNameGlob(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Name: []string{"*ing"},
Action: "drop",
},
},
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"foundry",
map[string]string{
"source": "machine B",
"location": "factory X",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 1337,
"temperature": 19.9,
"pieces": 96878,
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestTagPass(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Tags: map[string][]string{"status": {"OK"}},
Action: "pass",
},
},
DefaultAction: "drop",
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"packing",
map[string]string{
"source": "machine A",
"location": "main building",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 37,
"temperature": 23.1,
},
time.Unix(0, 0),
),
metric.New(
"foundry",
map[string]string{
"source": "machine B",
"location": "factory X",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 1337,
"temperature": 19.9,
"pieces": 96878,
},
time.Unix(0, 0),
),
metric.New(
"welding",
map[string]string{
"source": "machine D",
"location": "factory Y",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 825,
"temperature": 31.2,
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestTagDrop(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Tags: map[string][]string{"status": {"OK"}},
Action: "drop",
},
},
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"welding",
map[string]string{
"source": "machine C",
"location": "factory X",
"status": "failure",
},
map[string]interface{}{
"operating_hours": 1009,
"temperature": 67.3,
"message": "temperature alert",
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestTagMultiple(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Tags: map[string][]string{
"location": {"factory X", "factory Y"},
"status": {"OK"},
},
Action: "pass",
},
},
DefaultAction: "drop",
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"foundry",
map[string]string{
"source": "machine B",
"location": "factory X",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 1337,
"temperature": 19.9,
"pieces": 96878,
},
time.Unix(0, 0),
),
metric.New(
"welding",
map[string]string{
"source": "machine D",
"location": "factory Y",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 825,
"temperature": 31.2,
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestTagGlob(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Tags: map[string][]string{"location": {"factory *"}},
Action: "pass",
},
},
DefaultAction: "drop",
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"foundry",
map[string]string{
"source": "machine B",
"location": "factory X",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 1337,
"temperature": 19.9,
"pieces": 96878,
},
time.Unix(0, 0),
),
metric.New(
"welding",
map[string]string{
"source": "machine C",
"location": "factory X",
"status": "failure",
},
map[string]interface{}{
"operating_hours": 1009,
"temperature": 67.3,
"message": "temperature alert",
},
time.Unix(0, 0),
),
metric.New(
"welding",
map[string]string{
"source": "machine D",
"location": "factory Y",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 825,
"temperature": 31.2,
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestTagDoesNotExist(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Tags: map[string][]string{
"operator": {"peter"},
"status": {"OK"},
},
Action: "pass",
},
},
DefaultAction: "drop",
}
require.NoError(t, plugin.Init())
require.Empty(t, plugin.Apply(testmetrics...))
}
func TestFieldPass(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Fields: []string{"message", "pieces"},
Action: "pass",
},
},
DefaultAction: "drop",
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"foundry",
map[string]string{
"source": "machine B",
"location": "factory X",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 1337,
"temperature": 19.9,
"pieces": 96878,
},
time.Unix(0, 0),
),
metric.New(
"welding",
map[string]string{
"source": "machine C",
"location": "factory X",
"status": "failure",
},
map[string]interface{}{
"operating_hours": 1009,
"temperature": 67.3,
"message": "temperature alert",
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestFieldDrop(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Fields: []string{"message", "pieces"},
Action: "drop",
},
},
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"packing",
map[string]string{
"source": "machine A",
"location": "main building",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 37,
"temperature": 23.1,
},
time.Unix(0, 0),
),
metric.New(
"welding",
map[string]string{
"source": "machine D",
"location": "factory Y",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 825,
"temperature": 31.2,
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestFieldGlob(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Fields: []string{"{message,piece*}"},
Action: "pass",
},
},
DefaultAction: "drop",
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"foundry",
map[string]string{
"source": "machine B",
"location": "factory X",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 1337,
"temperature": 19.9,
"pieces": 96878,
},
time.Unix(0, 0),
),
metric.New(
"welding",
map[string]string{
"source": "machine C",
"location": "factory X",
"status": "failure",
},
map[string]interface{}{
"operating_hours": 1009,
"temperature": 67.3,
"message": "temperature alert",
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}
func TestRuleOrder(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Name: []string{"welding"},
Action: "drop",
},
{
Name: []string{"welding"},
Action: "pass",
},
},
DefaultAction: "drop",
}
require.NoError(t, plugin.Init())
require.Empty(t, plugin.Apply(testmetrics...))
}
func TestRuleMultiple(t *testing.T) {
plugin := &Filter{
Rules: []rule{
{
Name: []string{"welding"},
Action: "drop",
},
{
Name: []string{"foundry"},
Action: "drop",
},
},
DefaultAction: "pass",
}
require.NoError(t, plugin.Init())
expected := []telegraf.Metric{
metric.New(
"packing",
map[string]string{
"source": "machine A",
"location": "main building",
"status": "OK",
},
map[string]interface{}{
"operating_hours": 37,
"temperature": 23.1,
},
time.Unix(0, 0),
),
}
actual := plugin.Apply(testmetrics...)
testutil.RequireMetricsEqual(t, expected, actual)
}

View File

@ -0,0 +1,87 @@
package filter
import (
"fmt"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/filter"
)
type rule struct {
Name []string `toml:"name"`
Tags map[string][]string `toml:"tags"`
Fields []string `toml:"fields"`
Action string `toml:"action"`
nameFilter filter.Filter
fieldFilter filter.Filter
tagFilters map[string]filter.Filter
pass bool
}
func (r *rule) init() error {
// Check the action setting
switch r.Action {
case "pass":
r.pass = true
case "", "drop":
// Do nothing, those options are valid
default:
return fmt.Errorf("invalid action %q", r.Action)
}
// Compile the filters
var err error
r.nameFilter, err = filter.Compile(r.Name)
if err != nil {
return fmt.Errorf("creating name filter failed: %w", err)
}
r.fieldFilter, err = filter.Compile(r.Fields)
if err != nil {
return fmt.Errorf("creating fields filter failed: %w", err)
}
r.tagFilters = make(map[string]filter.Filter, len(r.Tags))
for k, values := range r.Tags {
r.tagFilters[k], err = filter.Compile(values)
if err != nil {
return fmt.Errorf("creating tag filter for tag %q failed: %w", k, err)
}
}
return nil
}
func (r *rule) apply(m telegraf.Metric) (pass, applies bool) {
// Check the metric name
if r.nameFilter != nil {
if !r.nameFilter.Match(m.Name()) {
return true, false
}
}
// Check the tags if given
tags := m.Tags()
for k, f := range r.tagFilters {
if value, found := tags[k]; !found || !f.Match(value) {
return true, false
}
}
// Check the field names
if r.fieldFilter != nil {
var matches bool
for _, field := range m.FieldList() {
if r.fieldFilter.Match(field.Key) {
matches = true
break
}
}
if !matches {
return true, false
}
}
return r.pass, true
}

View File

@ -0,0 +1,28 @@
# Filter metrics by the given criteria
[[processors.filter]]
## Default action if no rule applies
# default = "pass"
## Rules to apply on the incoming metrics (multiple rules are possible)
## The rules are evaluated in order and the first matching rule is applied.
## In case no rule matches the "default" is applied.
## All filter criteria in a rule must apply for the rule to match the metric
## i.e. the criteria are combined by a logical AND. If a criterion is
## omitted it is NOT applied at all and ignored.
[[processors.filter.rule]]
## List of metric names to match including glob expressions
# name = []
## List of tag key/values pairs to match including glob expressions
## ALL given tags keys must exist and at least one value must match
## for the metric to match the rule.
# tags = {}
## List of field keys to match including glob expressions
## At least one field must exist for the metric to match the rule.
# fields = []
## Action to apply for this rule
## "pass" will keep the metric and pass it on, while "drop" will remove
## the metric
# action = "drop"

View File

@ -1,60 +0,0 @@
# Noop Processor Plugin
The noop processor plugin does nothing to metrics. Instead it can be used to
apply the global configuration options after other processing. Global config
options like tagpass, fieldpass, and others are applied before a processor,
aggregator, or output. As such a user might want to apply these after doing
processing, but before an output or another processor.
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
In addition to the plugin-specific configuration settings, plugins support
additional global and plugin configuration settings. These settings are used to
modify metrics, tags, and field or create aliases and configure ordering, etc.
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
## Configuration
```toml @sample.conf
# Do nothing processor
[[processors.noop]]
## Metric Filtering
## The following options provide mechanisms to include or exclude entire
## metrics. For specific details and examples see the metric filtering docs:
## https://github.com/influxdata/telegraf/blob/master/docs/CONFIGURATION.md#metric-filtering
## Metric Selectors - These will drop entire metrics
## Filter on metric name or tag key + value
# namepass = []
# namedrop = []
# tagpass = {}
# tagdrop = {}
## Filter on Common Expression Language (CEL) expression
# metricpass = ""
## Metric Modifiers - These will drop tags and fields from metrics
## Filter on tag key or field key
# taginclude = []
# tagexclude = []
# fieldpass = []
# fielddrop = []
```
## Examples
Consider a use-case where you have processed a metric based on a tag, but no
longer need that tag for additional processing:
```toml
[[processors.ifname]]
order = 1
...
[[processors.noop]]
order = 2
tagexclude = ["useless_tag"]
```

View File

@ -1,28 +0,0 @@
//go:generate ../../../tools/readme_config_includer/generator
package noop
import (
_ "embed"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/processors"
)
//go:embed sample.conf
var sampleConfig string
type Noop struct{}
func (*Noop) SampleConfig() string {
return sampleConfig
}
func (p *Noop) Apply(in ...telegraf.Metric) []telegraf.Metric {
return in
}
func init() {
processors.Add("noop", func() telegraf.Processor {
return &Noop{}
})
}

View File

@ -1,72 +0,0 @@
package noop
import (
"testing"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/testutil"
"github.com/stretchr/testify/require"
)
func TestNoopNoMetric(t *testing.T) {
processor := Noop{}
m := []telegraf.Metric{}
actual := processor.Apply(m...)
require.Empty(t, actual)
testutil.RequireMetricsEqual(t, m, actual)
}
func TestNoopSingleMetric(t *testing.T) {
processor := Noop{}
m := []telegraf.Metric{
testutil.MustMetric(
"test",
map[string]string{
"tag": "tag_value",
},
map[string]interface{}{
"value": 42,
},
time.Now(),
telegraf.Gauge,
),
}
actual := processor.Apply(m...)
require.Len(t, actual, 1)
testutil.RequireMetricsEqual(t, m, actual)
}
func TestNoopMultipleMetrics(t *testing.T) {
processor := Noop{}
m := []telegraf.Metric{
testutil.MustMetric(
"test",
map[string]string{
"tag": "tag_value",
},
map[string]interface{}{
"value": 42,
},
time.Now(),
telegraf.Gauge,
),
testutil.MustMetric(
"test",
map[string]string{
"tag": "tag_value",
},
map[string]interface{}{
"value": 42,
},
time.Now(),
telegraf.Gauge,
),
}
actual := processor.Apply(m...)
require.Len(t, actual, 2)
testutil.RequireMetricsEqual(t, m, actual)
}

View File

@ -1,24 +0,0 @@
# Do nothing processor
[[processors.noop]]
## Metric Filtering
## The following options provide mechanisms to include or exclude entire
## metrics. For specific details and examples see the metric filtering docs:
## https://github.com/influxdata/telegraf/blob/master/docs/CONFIGURATION.md#metric-filtering
## Metric Selectors - These will drop entire metrics
## Filter on metric name or tag key + value
# namepass = []
# namedrop = []
# tagpass = {}
# tagdrop = {}
## Filter on Common Expression Language (CEL) expression
# metricpass = ""
## Metric Modifiers - These will drop tags and fields from metrics
## Filter on tag key or field key
# taginclude = []
# tagexclude = []
# fieldpass = []
# fielddrop = []