Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[processor/filterprocessor] Ability to filter spans #6341

Merged
merged 45 commits into from
Jun 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e2f2b63
processor/filterprocessor: Ability to filter spans
boostchicken Nov 16, 2021
4ba3a6a
processor/filterprocessor: Removing old useless code, fixing SkipScan…
boostchicken Nov 16, 2021
f0f8e91
Syntax cleanup
boostchicken Nov 16, 2021
e2e5d49
Documentation cleanup
boostchicken Nov 16, 2021
7c26c95
Clear up keep logic
boostchicken Nov 16, 2021
138dbd6
Removed extra loop that is no longer needed
boostchicken Nov 16, 2021
f1d5ebb
Fixing future pipeline processing
boostchicken Nov 16, 2021
382fe62
Added config test for traces
boostchicken Nov 16, 2021
2f3912a
Config and Factory testing
boostchicken Nov 16, 2021
00bc404
Check resource and span for service.name
boostchicken Nov 16, 2021
35595c8
Unit test for filtering and some filtering fixes
boostchicken Nov 16, 2021
a4dce31
Unit test for filtering and some filtering fixes
boostchicken Nov 16, 2021
a3d68bb
Code cleanup
boostchicken Nov 16, 2021
c612d40
Code cleanup
boostchicken Nov 16, 2021
3d1ecd7
Formatting code for readability
boostchicken Nov 16, 2021
529f54e
Refactor grabbing service names from spans and resources
boostchicken Dec 6, 2021
061e9d3
Added test for service name parsing from spans
boostchicken Dec 6, 2021
10bdebf
Fixing lint error
boostchicken Dec 8, 2021
07be63b
Fixing lint error
boostchicken Dec 8, 2021
298ae76
Fixing lint error
boostchicken Dec 8, 2021
254b44b
Re generating
boostchicken Dec 8, 2021
d1caddd
Re generating
boostchicken Dec 8, 2021
e8ea488
Update processor/filterprocessor/filter_processor_traces_test.go
boostchicken Jan 11, 2022
8ded3d1
Update processor/filterprocessor/filter_processor_traces.go
boostchicken Jan 11, 2022
5ce4e73
Update processor/filterprocessor/filter_processor_traces.go
boostchicken Jan 11, 2022
31452ed
Update README.md
boostchicken Jan 11, 2022
d2bb4ee
Update README.md
boostchicken Jan 11, 2022
40b964e
Update README.md
boostchicken Jan 11, 2022
01f8e40
Update README.md
boostchicken Jan 11, 2022
edb8fe7
Update CHANGELOG.md
boostchicken Jan 11, 2022
54bee73
Fixing small login hygiene issues
boostchicken Jan 11, 2022
2c603bd
Cleaning up asserts
boostchicken Jan 11, 2022
00968f0
Update filter_processor_traces_test.go
boostchicken Jan 11, 2022
e3adc44
Wordsmithing
boostchicken Jan 11, 2022
096619c
Moving to require
boostchicken Jan 11, 2022
de40fe1
Merge branch 'main' into filter_spans
jpkrohling Jan 31, 2022
1d0456d
Merge branch 'main' into filter_spans
boostchicken Jun 11, 2022
660bc0e
Fixing filter spans to match new API
boostchicken Jun 11, 2022
fe9ba1c
Fixing documentation
boostchicken Jun 11, 2022
f24f7f3
Fixing documentation
boostchicken Jun 11, 2022
fd5cc38
ran make common
boostchicken Jun 11, 2022
e66ede6
Removing bad unit test that is no longer needed
boostchicken Jun 11, 2022
030f61b
Fixing link that was broken due to Attributes Process readme.md update
boostchicken Jun 11, 2022
9f1c831
Tidying deps
boostchicken Jun 11, 2022
cefdbd4
Merge branch 'main' into filter_spans
boostchicken Jun 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Changelog

## Unreleased

- `filterprocessor`: Ability to filter `Spans` (#6341)
-
## 🛑 Breaking changes 🛑
- `transformprocessor`: `metric.is_monotonic` is now accessed via a bool literal instead of a string. (#10473)

Expand Down
5 changes: 3 additions & 2 deletions internal/coreinternal/processor/filterspan/filterspan.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ func SkipSpan(include Matcher, exclude Matcher, span ptrace.Span, resource pcomm
func (mp *propertiesMatcher) MatchSpan(span ptrace.Span, resource pcommon.Resource, library pcommon.InstrumentationScope) bool {
// If a set of properties was not in the mp, all spans are considered to match on that property
if mp.serviceFilters != nil {
// Check resource and spans for service.name
serviceName := serviceNameForResource(resource)

if !mp.serviceFilters.Matches(serviceName) {
return false
}
Expand All @@ -131,6 +133,5 @@ func serviceNameForResource(resource pcommon.Resource) string {
if !found {
return "<nil-service-name>"
}

return service.StringVal()
return service.AsString()
}
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,12 @@ func TestSpan_Matching_True(t *testing.T) {

func TestServiceNameForResource(t *testing.T) {
td := testdata.GenerateTracesOneSpanNoResource()
require.Equal(t, serviceNameForResource(td.ResourceSpans().At(0).Resource()), "<nil-service-name>")
name := serviceNameForResource(td.ResourceSpans().At(0).Resource())
require.Equal(t, name, "<nil-service-name>")

td = testdata.GenerateTracesOneSpan()
resource := td.ResourceSpans().At(0).Resource()
require.Equal(t, serviceNameForResource(resource), "<nil-service-name>")
name = serviceNameForResource(resource)
require.Equal(t, name, "<nil-service-name>")

resource.Attributes().InsertString(conventions.AttributeServiceName, "test-service")
require.Equal(t, serviceNameForResource(resource), "test-service")
}
45 changes: 43 additions & 2 deletions processor/filterprocessor/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
# Filter Processor

- Supported pipeline types: logs, metrics, spans
boostchicken marked this conversation as resolved.
Show resolved Hide resolved
=======
| Status | |
| ------------------------ | ----------------- |
| Stability | [alpha] |
| Supported pipeline types | metrics, logs |
| Supported pipeline types | metrics, logs, traces |
| Distributions | [core], [contrib] |

The filter processor can be configured to include or exclude:


- logs, based on resource attributes using the `strict` or `regexp` match types
- metrics based on metric name in the case of the `strict` or `regexp` match types,
or based on other metric attributes in the case of the `expr` match type.
Please refer to [config.go](./config.go) for the config spec.
- Spans based on tags, resources, and names, all with full regex support
boostchicken marked this conversation as resolved.
Show resolved Hide resolved

It takes a pipeline type, of which `logs` and `metrics` are supported, followed
It takes a pipeline type, of which `logs` `metrics`, and `traces` are supported, followed
by an action:

- `include`: Any names NOT matching filters are excluded from remainder of pipeline
Expand Down Expand Up @@ -209,6 +213,43 @@ processors:

In case the no metric names are provided, `matric_names` being empty, the filtering is only done at resource level.

### Filter Spans from Traces
boostchicken marked this conversation as resolved.
Show resolved Hide resolved

* This pipeline is able to drop spans and whole traces
* Note: If this drops a parent span, it does not search out it's children leading to a missing Span in your trace visualization

See the documentation in the [attribute processor](../attributesprocessor/README.md) for syntax

For spans, one of Services, SpanNames, Attributes, Resources or Libraries must be specified with a
non-empty value for a valid configuration.

```yaml
processors:
filter:
spans:
include:
match_type: strict
services:
- app_3
exclude:
match_type: regex
services:
- app_1
- app_2
span_names:
- hello_world
- hello/world
attributes:
- Key: container.name
Value: (app_container_1|app_container_2)
libraries:
- Name: opentelemetry
Version: 0.0-beta
resources:
- Key: container.host
Value: (localhost|127.0.0.1)
```

[alpha]:https://github.com/open-telemetry/opentelemetry-collector#alpha
[contrib]:https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
[core]:https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol
19 changes: 19 additions & 0 deletions processor/filterprocessor/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/processor/filterconfig"
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/processor/filtermetric"
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/processor/filterset"
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/processor/filterset/regexp"
)

// Config defines configuration for Resource processor.
Expand All @@ -29,6 +30,8 @@ type Config struct {
Metrics MetricFilters `mapstructure:"metrics"`

Logs LogFilters `mapstructure:"logs"`

Spans SpanFilters `mapstructure:"spans"`
}

// MetricFilters filters by Metric properties.
Expand All @@ -42,6 +45,22 @@ type MetricFilters struct {
// all other metrics should be included.
// If both Include and Exclude are specified, Include filtering occurs first.
Exclude *filtermetric.MatchProperties `mapstructure:"exclude"`

// RegexpConfig specifies options for the Regexp match type
RegexpConfig *regexp.Config `mapstructure:"regexp"`
}

// SpanFilters filters by Span attributes and various other fields, Regexp config is per matcher
type SpanFilters struct {
// Include match properties describe spans that should be included in the Collector Service pipeline,
// all other spans should be dropped from further processing.
// If both Include and Exclude are specified, Include filtering occurs first.
Include *filterconfig.MatchProperties `mapstructure:"include"`

// Exclude match properties describe spans that should be excluded from the Collector Service pipeline,
// all other spans should be included.
// If both Include and Exclude are specified, Include filtering occurs first.
Exclude *filterconfig.MatchProperties `mapstructure:"exclude"`
}

// LogFilters filters by Log properties.
Expand Down
48 changes: 48 additions & 0 deletions processor/filterprocessor/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package filterprocessor

import (
"path"
"path/filepath"
"testing"

Expand All @@ -26,6 +27,7 @@ import (

"github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/processor/filterconfig"
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/processor/filtermetric"
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/processor/filterset"
fsregexp "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/processor/filterset/regexp"
)

Expand Down Expand Up @@ -272,6 +274,52 @@ func TestLoadingConfigRegexp(t *testing.T) {
}
}

func TestLoadingSpans(t *testing.T) {
factories, err := componenttest.NopFactories()
require.NoError(t, err)
factory := NewFactory()
factories.Processors[typeStr] = factory
cfg, err := servicetest.LoadConfigAndValidate(path.Join(".", "testdata", "config_traces.yaml"), factories)
require.NoError(t, err)
require.NotNil(t, cfg)

tests := []struct {
expCfg config.Processor
}{
{
expCfg: &Config{
ProcessorSettings: config.NewProcessorSettings(config.NewComponentIDWithName(typeStr, "spans")),
Spans: SpanFilters{
Include: &filterconfig.MatchProperties{
Config: filterset.Config{
MatchType: filterset.Strict,
},
Services: []string{"test", "test2"},
Attributes: []filterconfig.Attribute{
{Key: "should_include", Value: "(true|probably_true)"},
},
},
Exclude: &filterconfig.MatchProperties{
Config: filterset.Config{
MatchType: filterset.Regexp,
},
Attributes: []filterconfig.Attribute{
{Key: "should_exclude", Value: "(probably_false|false)"},
},
},
},
},
},
}

for _, test := range tests {
t.Run(test.expCfg.ID().String(), func(t *testing.T) {
cfg := cfg.Processors[test.expCfg.ID()]
assert.Equal(t, test.expCfg, cfg)
})
}
}

func TestLoadingConfigExpr(t *testing.T) {
factories, err := componenttest.NopFactories()
require.NoError(t, err)
Expand Down
18 changes: 18 additions & 0 deletions processor/filterprocessor/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func NewFactory() component.ProcessorFactory {
createDefaultConfig,
component.WithMetricsProcessor(createMetricsProcessor),
component.WithLogsProcessor(createLogsProcessor),
component.WithTracesProcessor(createTracesProcessor),
)
}

Expand Down Expand Up @@ -79,3 +80,20 @@ func createLogsProcessor(
fp.ProcessLogs,
processorhelper.WithCapabilities(processorCapabilities))
}

func createTracesProcessor(
_ context.Context,
set component.ProcessorCreateSettings,
cfg config.Processor,
nextConsumer consumer.Traces,
) (component.TracesProcessor, error) {
fp, err := newFilterSpansProcessor(set.Logger, cfg.(*Config))
if err != nil {
return nil, err
}
return processorhelper.NewTracesProcessor(
cfg,
nextConsumer,
fp.processTraces,
processorhelper.WithCapabilities(processorCapabilities))
}
28 changes: 22 additions & 6 deletions processor/filterprocessor/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"fmt"
"path/filepath"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -70,6 +71,12 @@ func TestCreateProcessors(t *testing.T) {
}, {
configName: "config_logs_record_attributes_regexp.yaml",
succeed: true,
}, {
configName: "config_traces.yaml",
succeed: true,
}, {
configName: "config_traces_invalid.yaml",
succeed: false,
},
}

Expand All @@ -87,13 +94,22 @@ func TestCreateProcessors(t *testing.T) {
factory := NewFactory()

tp, tErr := factory.CreateTracesProcessor(context.Background(), componenttest.NewNopProcessorCreateSettings(), cfg, consumertest.NewNop())
// Not implemented error
assert.NotNil(t, tErr)
assert.Nil(t, tp)

mp, mErr := factory.CreateMetricsProcessor(context.Background(), componenttest.NewNopProcessorCreateSettings(), cfg, consumertest.NewNop())
assert.Equal(t, test.succeed, mp != nil)
assert.Equal(t, test.succeed, mErr == nil)
if strings.Contains(test.configName, "traces") {
assert.Equal(t, test.succeed, tp != nil)
assert.Equal(t, test.succeed, tErr == nil)

assert.NotNil(t, mp)
assert.Nil(t, mErr)
} else {
// Should not break configs with no trace data
assert.NotNil(t, tp)
assert.Nil(t, tErr)

assert.Equal(t, test.succeed, mp != nil)
assert.Equal(t, test.succeed, mErr == nil)
}

})
}
}
Expand Down
Loading