diff --git a/processor/filterprocessor/config.go b/processor/filterprocessor/config.go new file mode 100644 index 00000000000..02889ce275f --- /dev/null +++ b/processor/filterprocessor/config.go @@ -0,0 +1,39 @@ +// Copyright 2020 OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filterprocessor + +import ( + "go.opentelemetry.io/collector/config/configmodels" + "go.opentelemetry.io/collector/internal/processor/filtermetric" +) + +// Config defines configuration for Resource processor. +type Config struct { + configmodels.ProcessorSettings `mapstructure:",squash"` + Metrics MetricFilters `mapstructure:"metrics"` +} + +// MetricFilter filters by Metric properties. +type MetricFilters struct { + // Include match properties describe metrics that should be included in the Collector Service pipeline, + // all other metrics should be dropped from further processing. + // If both Include and Exclude are specified, Include filtering occurs first. + Include *filtermetric.MatchProperties `mapstructure:"include"` + + // Exclude match properties describe metrics that should be excluded from the Collector Service pipeline, + // all other metrics should be included. + // If both Include and Exclude are specified, Include filtering occurs first. + Exclude *filtermetric.MatchProperties `mapstructure:"exclude"` +} diff --git a/processor/filterprocessor/config_test.go b/processor/filterprocessor/config_test.go new file mode 100644 index 00000000000..4329b6ab3c7 --- /dev/null +++ b/processor/filterprocessor/config_test.go @@ -0,0 +1,230 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filterprocessor + +import ( + "path" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configmodels" + "go.opentelemetry.io/collector/internal/processor/filtermetric" + "go.opentelemetry.io/collector/internal/processor/filterset" + fsregexp "go.opentelemetry.io/collector/internal/processor/filterset/regexp" +) + +// TestLoadingConfigRegexp tests loading testdata/config_strict.yaml +func TestLoadingConfigStrict(t *testing.T) { + // list of filters used repeatedly on testdata/config_strict.yaml + testDataFilters := []string{ + "hello_world", + "hello/world", + } + + testDataMetricProperties := &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + MetricNames: testDataFilters, + } + + factories, err := config.ExampleComponents() + assert.Nil(t, err) + + factory := &Factory{} + factories.Processors[configmodels.Type(typeStr)] = factory + config, err := config.LoadConfigFile(t, path.Join(".", "testdata", "config_strict.yaml"), factories) + + assert.Nil(t, err) + require.NotNil(t, config) + + tests := []struct { + filterName string + expCfg *Config + }{ + { + filterName: "filter/empty", + expCfg: &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + NameVal: "filter/empty", + TypeVal: typeStr, + }, + Metrics: MetricFilters{ + Include: &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + }, + }, + }, + }, { + filterName: "filter/include", + expCfg: &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + NameVal: "filter/include", + TypeVal: typeStr, + }, + Metrics: MetricFilters{ + Include: testDataMetricProperties, + }, + }, + }, { + filterName: "filter/exclude", + expCfg: &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + NameVal: "filter/exclude", + TypeVal: typeStr, + }, + Metrics: MetricFilters{ + Exclude: testDataMetricProperties, + }, + }, + }, { + filterName: "filter/includeexclude", + expCfg: &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + NameVal: "filter/includeexclude", + TypeVal: typeStr, + }, + Metrics: MetricFilters{ + Include: testDataMetricProperties, + Exclude: &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + MetricNames: []string{"hello_world"}, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.filterName, func(t *testing.T) { + cfg := config.Processors[test.filterName] + assert.Equal(t, test.expCfg, cfg) + }) + } +} + +// TestLoadingConfigRegexp tests loading testdata/config_regexp.yaml +func TestLoadingConfigRegexp(t *testing.T) { + // list of filters used repeatedly on testdata/config.yaml + testDataFilters := []string{ + "prefix/.*", + "prefix_.*", + ".*/suffix", + ".*_suffix", + ".*/contains/.*", + ".*_contains_.*", + "full/name/match", + "full_name_match", + } + + testDataMetricProperties := &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + MetricNames: testDataFilters, + } + + factories, err := config.ExampleComponents() + assert.Nil(t, err) + + factory := &Factory{} + factories.Processors[typeStr] = factory + config, err := config.LoadConfigFile(t, path.Join(".", "testdata", "config_regexp.yaml"), factories) + + assert.Nil(t, err) + require.NotNil(t, config) + + tests := []struct { + filterName string + expCfg *Config + }{ + { + filterName: "filter/include", + expCfg: &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + NameVal: "filter/include", + TypeVal: typeStr, + }, + Metrics: MetricFilters{ + Include: testDataMetricProperties, + }, + }, + }, { + filterName: "filter/exclude", + expCfg: &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + NameVal: "filter/exclude", + TypeVal: typeStr, + }, + Metrics: MetricFilters{ + Exclude: testDataMetricProperties, + }, + }, + }, { + filterName: "filter/unlimitedcache", + expCfg: &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + NameVal: "filter/unlimitedcache", + TypeVal: typeStr, + }, + Metrics: MetricFilters{ + Include: &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + RegexpConfig: &fsregexp.Config{ + CacheEnabled: true, + }, + }, + MetricNames: testDataFilters, + }, + }, + }, + }, { + filterName: "filter/limitedcache", + expCfg: &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + NameVal: "filter/limitedcache", + TypeVal: typeStr, + }, + Metrics: MetricFilters{ + Exclude: &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + RegexpConfig: &fsregexp.Config{ + CacheEnabled: true, + CacheMaxNumEntries: 10, + }, + }, + MetricNames: testDataFilters, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.filterName, func(t *testing.T) { + cfg := config.Processors[test.filterName] + assert.Equal(t, test.expCfg, cfg) + }) + } +} diff --git a/processor/filterprocessor/doc.go b/processor/filterprocessor/doc.go new file mode 100644 index 00000000000..aa74b8715a1 --- /dev/null +++ b/processor/filterprocessor/doc.go @@ -0,0 +1,17 @@ +// Copyright 2019 OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package filterprocessor implements a processor for filtering +// (dropping) metrics and/or spans by various properties. +package filterprocessor diff --git a/processor/filterprocessor/factory.go b/processor/filterprocessor/factory.go new file mode 100644 index 00000000000..81e6fa4c716 --- /dev/null +++ b/processor/filterprocessor/factory.go @@ -0,0 +1,70 @@ +// Copyright 2019 OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filterprocessor + +import ( + "context" + + "go.uber.org/zap" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configerror" + "go.opentelemetry.io/collector/config/configmodels" + "go.opentelemetry.io/collector/consumer" +) + +const ( + // The value of "type" key in configuration. + typeStr = "filter" +) + +// Factory is the factory for filter processor. +type Factory struct { +} + +// Type gets the type of the Option config created by this factory. +func (f Factory) Type() configmodels.Type { + return typeStr +} + +// CreateDefaultConfig creates the default configuration for processor. +func (f Factory) CreateDefaultConfig() configmodels.Processor { + return &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + TypeVal: typeStr, + NameVal: typeStr, + }, + } +} + +// CreateTraceProcessor creates a trace processor based on this config. +func (f *Factory) CreateTraceProcessor( + ctx context.Context, + params component.ProcessorCreateParams, + nextConsumer consumer.TraceConsumer, + cfg configmodels.Processor, +) (component.TraceProcessor, error) { + return nil, configerror.ErrDataTypeIsNotSupported +} + +// CreateMetricsProcessor creates a metrics processor based on this config. +func (f Factory) CreateMetricsProcessor( + logger *zap.Logger, + nextConsumer consumer.MetricsConsumerOld, + cfg configmodels.Processor, +) (component.MetricsProcessorOld, error) { + oCfg := cfg.(*Config) + return newFilterMetricProcessor(nextConsumer, oCfg) +} diff --git a/processor/filterprocessor/factory_test.go b/processor/filterprocessor/factory_test.go new file mode 100644 index 00000000000..c1734750ab6 --- /dev/null +++ b/processor/filterprocessor/factory_test.go @@ -0,0 +1,93 @@ +// Copyright 2020, OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filterprocessor + +import ( + "context" + "fmt" + "path" + "testing" + + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configcheck" + "go.opentelemetry.io/collector/config/configmodels" +) + +func TestType(t *testing.T) { + factory := Factory{} + pType := factory.Type() + + assert.Equal(t, pType, configmodels.Type("filter")) +} + +func TestCreateDefaultConfig(t *testing.T) { + factory := Factory{} + cfg := factory.CreateDefaultConfig() + assert.Equal(t, cfg, &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + NameVal: typeStr, + TypeVal: typeStr, + }, + }) + assert.NoError(t, configcheck.ValidateConfig(cfg)) +} + +func TestCreateProcessors(t *testing.T) { + tests := []struct { + configName string + succeed bool + }{ + { + configName: "config_regexp.yaml", + succeed: true, + }, { + configName: "config_strict.yaml", + succeed: true, + }, { + configName: "config_invalid.yaml", + succeed: false, + }, + } + + for _, test := range tests { + factories, err := config.ExampleComponents() + assert.Nil(t, err) + + factory := &Factory{} + factories.Processors[typeStr] = factory + config, err := config.LoadConfigFile(t, path.Join(".", "testdata", test.configName), factories) + assert.Nil(t, err) + + for name, cfg := range config.Processors { + t.Run(fmt.Sprintf("%s/%s", test.configName, name), func(t *testing.T) { + factory := &Factory{} + creationParams := component.ProcessorCreateParams{Logger: zap.NewNop()} + + tp, tErr := factory.CreateTraceProcessor(context.Background(), creationParams, nil, cfg) + // Not implemented error + assert.NotNil(t, tErr) + assert.Nil(t, tp) + + mp, mErr := factory.CreateMetricsProcessor(zap.NewNop(), nil, cfg) + assert.Equal(t, test.succeed, mp != (*filterMetricProcessor)(nil)) + assert.Equal(t, test.succeed, mErr == nil) + }) + } + } +} diff --git a/processor/filterprocessor/filter_processor.go b/processor/filterprocessor/filter_processor.go new file mode 100644 index 00000000000..c2232201664 --- /dev/null +++ b/processor/filterprocessor/filter_processor.go @@ -0,0 +1,121 @@ +// Copyright 2020 OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filterprocessor + +import ( + "context" + + metricspb "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/consumer/consumerdata" + "go.opentelemetry.io/collector/internal/processor/filtermetric" +) + +type filterMetricProcessor struct { + cfg *Config + next consumer.MetricsConsumerOld + include *filtermetric.Matcher + exclude *filtermetric.Matcher +} + +var _ component.MetricsProcessorOld = (*filterMetricProcessor)(nil) + +func newFilterMetricProcessor(next consumer.MetricsConsumerOld, cfg *Config) (*filterMetricProcessor, error) { + inc, err := createMatcher(cfg.Metrics.Include) + if err != nil { + return nil, err + } + + exc, err := createMatcher(cfg.Metrics.Exclude) + if err != nil { + return nil, err + } + + return &filterMetricProcessor{ + cfg: cfg, + next: next, + include: inc, + exclude: exc, + }, nil +} + +func createMatcher(mp *filtermetric.MatchProperties) (*filtermetric.Matcher, error) { + // Nothing specified in configuration + if mp == nil { + return nil, nil + } + + matcher, err := filtermetric.NewMatcher(mp) + if err != nil { + return nil, err + } + + return &matcher, nil +} + +// GetCapabilities returns the Capabilities assocciated with the resource processor. +func (fmp *filterMetricProcessor) GetCapabilities() component.ProcessorCapabilities { + return component.ProcessorCapabilities{MutatesConsumedData: false} +} + +// Start is invoked during service startup. +func (*filterMetricProcessor) Start(ctx context.Context, host component.Host) error { + return nil +} + +// Shutdown is invoked during service shutdown. +func (*filterMetricProcessor) Shutdown(ctx context.Context) error { + return nil +} + +// ConsumeMetricsData implements the MetricsProcessor interface +func (fmp *filterMetricProcessor) ConsumeMetricsData(ctx context.Context, md consumerdata.MetricsData) error { + return fmp.next.ConsumeMetricsData(ctx, consumerdata.MetricsData{ + Node: md.Node, + Resource: md.Resource, + Metrics: fmp.filterMetrics(md.Metrics), + }) +} + +// filterMetrics filters the given spans based off the filterMetricProcessor's filters. +func (fmp *filterMetricProcessor) filterMetrics(metrics []*metricspb.Metric) []*metricspb.Metric { + keep := make([]*metricspb.Metric, 0, len(metrics)) + for _, m := range metrics { + if fmp.shouldKeepMetric(m) { + keep = append(keep, m) + } + } + + return keep +} + +// shouldKeepMetric determines whether a metric should be kept based off the filterMetricProcessor's filters. +func (fmp *filterMetricProcessor) shouldKeepMetric(metric *metricspb.Metric) bool { + if fmp.include != nil { + if !fmp.include.MatchMetric(metric) { + return false + } + } + + if fmp.exclude != nil { + if fmp.exclude.MatchMetric(metric) { + return false + } + } + + return true +} diff --git a/processor/filterprocessor/filter_processor_test.go b/processor/filterprocessor/filter_processor_test.go new file mode 100644 index 00000000000..fae6c93ecfa --- /dev/null +++ b/processor/filterprocessor/filter_processor_test.go @@ -0,0 +1,269 @@ +// Copyright 2020 OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filterprocessor + +import ( + "context" + "testing" + + metricspb "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/config/configmodels" + "go.opentelemetry.io/collector/consumer/consumerdata" + etest "go.opentelemetry.io/collector/exporter/exportertest" + "go.opentelemetry.io/collector/internal/processor/filtermetric" + "go.opentelemetry.io/collector/internal/processor/filterset" +) + +type metricNameTest struct { + name string + inc *filtermetric.MatchProperties + exc *filtermetric.MatchProperties + inMN []string // input Metric names + outMN []string // output Metric names +} + +var ( + validFilters = []string{ + "prefix/.*", + "prefix_.*", + ".*/suffix", + ".*_suffix", + ".*/contains/.*", + ".*_contains_.*", + "full/name/match", + "full_name_match", + } + + inMetricNames = []string{ + "full_name_match", + "not_exact_string_match", + "prefix/test/match", + "prefix_test_match", + "prefixprefix/test/match", + "test/match/suffix", + "test_match_suffix", + "test/match/suffixsuffix", + "test/contains/match", + "test_contains_match", + "random", + "full/name/match", + "full_name_match", // repeats + "not_exact_string_match", + } + + regexpMetricsFilterProperties = &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + MetricNames: validFilters, + } + + standardTests = []metricNameTest{ + { + name: "includeFilter", + inc: regexpMetricsFilterProperties, + inMN: inMetricNames, + outMN: []string{ + "full_name_match", + "prefix/test/match", + "prefix_test_match", + "prefixprefix/test/match", + "test/match/suffix", + "test_match_suffix", + "test/match/suffixsuffix", + "test/contains/match", + "test_contains_match", + "full/name/match", + "full_name_match", + }, + }, { + name: "excludeFilter", + exc: regexpMetricsFilterProperties, + inMN: inMetricNames, + outMN: []string{ + "not_exact_string_match", + "random", + "not_exact_string_match", + }, + }, { + name: "includeAndExclude", + inc: regexpMetricsFilterProperties, + exc: &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + MetricNames: []string{ + "prefix_test_match", + "test_contains_match", + }, + }, + inMN: inMetricNames, + outMN: []string{ + "full_name_match", + "prefix/test/match", + // "prefix_test_match", excluded by exclude filter + "prefixprefix/test/match", + "test/match/suffix", + "test_match_suffix", + "test/match/suffixsuffix", + "test/contains/match", + // "test_contains_match", excluded by exclude filter + "full/name/match", + "full_name_match", + }, + }, { + name: "emptyFilterInclude", + inc: &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + }, + inMN: inMetricNames, + outMN: []string{}, + }, { + name: "emptyFilterExclude", + exc: &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + }, + inMN: inMetricNames, + outMN: inMetricNames, + }, + } +) + +func TestFilterMetricProcessor(t *testing.T) { + for _, test := range standardTests { + t.Run(test.name, func(t *testing.T) { + // next stores the results of the filter metric processor + next := &etest.SinkMetricsExporterOld{} + cfg := &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + TypeVal: typeStr, + NameVal: typeStr, + }, + Metrics: MetricFilters{ + Include: test.inc, + Exclude: test.exc, + }, + } + fmp, err := newFilterMetricProcessor(next, cfg) + assert.NotNil(t, fmp) + assert.Nil(t, err) + + caps := fmp.GetCapabilities() + assert.Equal(t, false, caps.MutatesConsumedData) + ctx := context.Background() + assert.NoError(t, fmp.Start(ctx, nil)) + + md := consumerdata.MetricsData{ + Metrics: make([]*metricspb.Metric, len(test.inMN)), + } + + for idx, in := range test.inMN { + md.Metrics[idx] = &metricspb.Metric{ + MetricDescriptor: &metricspb.MetricDescriptor{ + Name: in, + }, + } + } + + cErr := fmp.ConsumeMetricsData(context.Background(), md) + assert.Nil(t, cErr) + + gotMetrics := next.AllMetrics()[0].Metrics + require.Equal(t, len(test.outMN), len(gotMetrics)) + for idx, out := range gotMetrics { + assert.Equal(t, test.outMN[idx], out.MetricDescriptor.Name) + } + + assert.NoError(t, fmp.Shutdown(ctx)) + }) + } +} + +func BenchmarkFilter_MetricNames(b *testing.B) { + // runs 1000 metrics through a filterprocessor with both include and exclude filters. + stressTest := metricNameTest{ + name: "includeAndExcludeFilter1000Metrics", + inc: regexpMetricsFilterProperties, + exc: &filtermetric.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + MetricNames: []string{ + "prefix_test_match", + "test_contains_match", + }, + }, + outMN: []string{ + "full_name_match", + "prefix/test/match", + // "prefix_test_match", excluded by exclude filter + "prefixprefix/test/match", + "test/match/suffix", + "test_match_suffix", + "test/match/suffixsuffix", + "test/contains/match", + // "test_contains_match", excluded by exclude filter + "full/name/match", + "full_name_match", + }, + } + + for len(stressTest.inMN) < 1000 { + stressTest.inMN = append(stressTest.inMN, inMetricNames...) + } + + benchmarkTests := append(standardTests, stressTest) + + for _, test := range benchmarkTests { + // next stores the results of the filter metric processor + next := &etest.SinkMetricsExporterOld{} + cfg := &Config{ + ProcessorSettings: configmodels.ProcessorSettings{ + TypeVal: typeStr, + NameVal: typeStr, + }, + Metrics: MetricFilters{ + Include: test.inc, + Exclude: test.exc, + }, + } + fmp, err := newFilterMetricProcessor(next, cfg) + assert.NotNil(b, fmp) + assert.Nil(b, err) + + md := consumerdata.MetricsData{ + Metrics: make([]*metricspb.Metric, len(test.inMN)), + } + + for idx, in := range test.inMN { + md.Metrics[idx] = &metricspb.Metric{ + MetricDescriptor: &metricspb.MetricDescriptor{ + Name: in, + }, + } + } + + b.Run(test.name, func(b *testing.B) { + assert.NoError(b, fmp.ConsumeMetricsData(context.Background(), md)) + }) + } +} diff --git a/processor/filterprocessor/testdata/config_invalid.yaml b/processor/filterprocessor/testdata/config_invalid.yaml new file mode 100644 index 00000000000..a2ed32c8c40 --- /dev/null +++ b/processor/filterprocessor/testdata/config_invalid.yaml @@ -0,0 +1,26 @@ +receivers: + examplereceiver: + +processors: + filter/include: + # any names NOT matching filters are excluded from remainder of pipeline + metrics: + include: + match_type: regexp + metric_names: + # re2 regexp patterns + - (\W|^)stock\stips(\W|$ + +exporters: + exampleexporter: + +service: + pipelines: + traces: + receivers: [examplereceiver] + processors: [filter/include] + exporters: [exampleexporter] + metrics: + receivers: [examplereceiver] + processors: [filter/include] + exporters: [exampleexporter] diff --git a/processor/filterprocessor/testdata/config_regexp.yaml b/processor/filterprocessor/testdata/config_regexp.yaml new file mode 100644 index 00000000000..6ad5a90c1f7 --- /dev/null +++ b/processor/filterprocessor/testdata/config_regexp.yaml @@ -0,0 +1,79 @@ +receivers: + examplereceiver: + +processors: + filter: + filter/include: + # any names NOT matching filters are excluded from remainder of pipeline + metrics: + include: + match_type: regexp + metric_names: + # re2 regexp patterns + - prefix/.* + - prefix_.* + - .*/suffix + - .*_suffix + - .*/contains/.* + - .*_contains_.* + - full/name/match + - full_name_match + filter/exclude: + # any names matching filters are excluded from remainder of pipeline + metrics: + exclude: + match_type: regexp + metric_names: + - prefix/.* + - prefix_.* + - .*/suffix + - .*_suffix + - .*/contains/.* + - .*_contains_.* + - full/name/match + - full_name_match + filter/unlimitedcache: + metrics: + include: + match_type: regexp + regexp: + cacheenabled: true + metric_names: + - prefix/.* + - prefix_.* + - .*/suffix + - .*_suffix + - .*/contains/.* + - .*_contains_.* + - full/name/match + - full_name_match + filter/limitedcache: + metrics: + exclude: + match_type: regexp + metric_names: + - prefix/.* + - prefix_.* + - .*/suffix + - .*_suffix + - .*/contains/.* + - .*_contains_.* + - full/name/match + - full_name_match + regexp: + cacheenabled: true + cachemaxnumentries: 10 + +exporters: + exampleexporter: + +service: + pipelines: + traces: + receivers: [examplereceiver] + processors: [filter] + exporters: [exampleexporter] + metrics: + receivers: [examplereceiver] + processors: [filter] + exporters: [exampleexporter] diff --git a/processor/filterprocessor/testdata/config_strict.yaml b/processor/filterprocessor/testdata/config_strict.yaml new file mode 100644 index 00000000000..5eddd3b6cdf --- /dev/null +++ b/processor/filterprocessor/testdata/config_strict.yaml @@ -0,0 +1,51 @@ +receivers: + examplereceiver: + +processors: + filter/empty: + metrics: + include: + match_type: strict + filter/include: + metrics: + # any names NOT matching filters are excluded from remainder of pipeline + include: + match_type: strict + metric_names: + - hello_world + - hello/world + filter/exclude: + metrics: + # any names matching filters are excluded from remainder of pipeline + exclude: + match_type: strict + metric_names: + - hello_world + - hello/world + filter/includeexclude: + metrics: + # if both include and exclude are specified, include filters are applied first + # the following configuration would only allow metrics named "hello/world" to pass through + include: + match_type: strict + metric_names: + - hello_world + - hello/world + exclude: + match_type: strict + metric_names: + - hello_world + +exporters: + exampleexporter: + +service: + pipelines: + traces: + receivers: [examplereceiver] + processors: [filter/empty] + exporters: [exampleexporter] + metrics: + receivers: [examplereceiver] + processors: [filter/empty] + exporters: [exampleexporter]