From 89d091cfbc5f9780b4a64ff0cfe8b0faadaa8b98 Mon Sep 17 00:00:00 2001 From: Tanner Bruce Date: Tue, 8 Mar 2022 11:30:26 -0600 Subject: [PATCH] filterspan: allow span kind matching --- .../processor/filterconfig/config.go | 22 +++++++--- .../processor/filterspan/filterspan.go | 16 +++++++ .../processor/filterspan/filterspan_test.go | 43 +++++++++++++++++-- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/internal/coreinternal/processor/filterconfig/config.go b/internal/coreinternal/processor/filterconfig/config.go index d767b101f152..fd066cee56ab 100644 --- a/internal/coreinternal/processor/filterconfig/config.go +++ b/internal/coreinternal/processor/filterconfig/config.go @@ -115,8 +115,18 @@ type MatchProperties struct { // A match occurs if the span's implementation library matches at least one item in this list. // This is an optional field. Libraries []InstrumentationLibrary `mapstructure:"libraries"` + + // SpanKinds specify the list of items to match the span kind against. + // A match occurs if the span's span kind matches at least one item in this list. + SpanKinds []string `mapstructure:"span_kinds"` } +var ( + ErrMissingRequiredField = errors.New(`at least one of "attributes", "libraries", or "resources" field must be specified`) + ErrInvalidLogField = errors.New("services, span_names, and span_kinds are not valid for log records") + ErrMissingRequiredLogField = errors.New(`at least one of "log_names", "attributes", "libraries", "span_kinds", or "resources" field must be specified`) +) + // ValidateForSpans validates properties for spans. func (mp *MatchProperties) ValidateForSpans() error { if len(mp.LogNames) > 0 { @@ -124,8 +134,8 @@ func (mp *MatchProperties) ValidateForSpans() error { } if len(mp.Services) == 0 && len(mp.SpanNames) == 0 && len(mp.Attributes) == 0 && - len(mp.Libraries) == 0 && len(mp.Resources) == 0 { - return errors.New(`at least one of "services", "span_names", "attributes", "libraries" or "resources" field must be specified`) + len(mp.Libraries) == 0 && len(mp.Resources) == 0 && len(mp.SpanKinds) == 0 { + return ErrMissingRequiredField } return nil @@ -133,12 +143,12 @@ func (mp *MatchProperties) ValidateForSpans() error { // ValidateForLogs validates properties for logs. func (mp *MatchProperties) ValidateForLogs() error { - if len(mp.SpanNames) > 0 || len(mp.Services) > 0 { - return errors.New("neither services nor span_names should be specified for log records") + if len(mp.SpanNames) > 0 || len(mp.Services) > 0 || len(mp.SpanKinds) > 0 { + return ErrInvalidLogField } - if len(mp.Attributes) == 0 && len(mp.Libraries) == 0 && len(mp.Resources) == 0 { - return errors.New(`at least one of "attributes", "libraries" or "resources" field must be specified`) + if len(mp.Attributes) == 0 && len(mp.Libraries) == 0 && len(mp.Resources) == 0 && len(mp.SpanKinds) == 0 { + return ErrMissingRequiredLogField } return nil diff --git a/internal/coreinternal/processor/filterspan/filterspan.go b/internal/coreinternal/processor/filterspan/filterspan.go index 8d1d859521a5..ba9cf4e43245 100644 --- a/internal/coreinternal/processor/filterspan/filterspan.go +++ b/internal/coreinternal/processor/filterspan/filterspan.go @@ -42,6 +42,9 @@ type propertiesMatcher struct { // Span names to compare to. nameFilters filterset.FilterSet + + // Span kinds to compare to + kindFilters filterset.FilterSet } // NewMatcher creates a span Matcher that matches based on the given MatchProperties. @@ -75,10 +78,19 @@ func NewMatcher(mp *filterconfig.MatchProperties) (Matcher, error) { } } + var kindFS filterset.FilterSet + if len(mp.SpanKinds) > 0 { + kindFS, err = filterset.CreateFilterSet(mp.SpanKinds, &mp.Config) + if err != nil { + return nil, fmt.Errorf("error creating span kind filters: %v", err) + } + } + return &propertiesMatcher{ PropertiesMatcher: rm, serviceFilters: serviceFS, nameFilters: nameFS, + kindFilters: kindFS, }, nil } @@ -121,6 +133,10 @@ func (mp *propertiesMatcher) MatchSpan(span pdata.Span, resource pdata.Resource, return false } + if mp.kindFilters != nil && !mp.kindFilters.Matches(span.Kind().String()) { + return false + } + return mp.PropertiesMatcher.Match(span.Attributes(), resource, library) } diff --git a/internal/coreinternal/processor/filterspan/filterspan_test.go b/internal/coreinternal/processor/filterspan/filterspan_test.go index a72ab0101d2f..93c143b01e58 100644 --- a/internal/coreinternal/processor/filterspan/filterspan_test.go +++ b/internal/coreinternal/processor/filterspan/filterspan_test.go @@ -42,14 +42,14 @@ func TestSpan_validateMatchesConfiguration_InvalidConfig(t *testing.T) { { name: "empty_property", property: filterconfig.MatchProperties{}, - errorString: "at least one of \"services\", \"span_names\", \"attributes\", \"libraries\" or \"resources\" field must be specified", + errorString: filterconfig.ErrMissingRequiredField.Error(), }, { name: "empty_service_span_names_and_attributes", property: filterconfig.MatchProperties{ Services: []string{}, }, - errorString: "at least one of \"services\", \"span_names\", \"attributes\", \"libraries\" or \"resources\" field must be specified", + errorString: filterconfig.ErrMissingRequiredField.Error(), }, { name: "log_properties", @@ -112,7 +112,6 @@ func TestSpan_Matching_False(t *testing.T) { Attributes: []filterconfig.Attribute{}, }, }, - { name: "service_name_doesnt_match_strict", properties: &filterconfig.MatchProperties{ @@ -143,6 +142,23 @@ func TestSpan_Matching_False(t *testing.T) { Attributes: []filterconfig.Attribute{}, }, }, + + { + name: "span_kind_doesnt_match_regexp", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + Attributes: []filterconfig.Attribute{}, + SpanKinds: []string{pdata.SpanKindProducer.String()}, + }, + }, + { + name: "span_kind_doesnt_match_strict", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Strict), + Attributes: []filterconfig.Attribute{}, + SpanKinds: []string{pdata.SpanKindProducer.String()}, + }, + }, } span := pdata.NewSpan() @@ -217,6 +233,26 @@ func TestSpan_Matching_True(t *testing.T) { Attributes: []filterconfig.Attribute{}, }, }, + { + name: "span_kind_match_strict", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Strict), + SpanKinds: []string{ + pdata.SpanKindClient.String(), + }, + Attributes: []filterconfig.Attribute{}, + }, + }, + { + name: "span_kind_match_regexp", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + SpanKinds: []string{ + "CLIENT", + }, + Attributes: []filterconfig.Attribute{}, + }, + }, } span := pdata.NewSpan() @@ -226,6 +262,7 @@ func TestSpan_Matching_True(t *testing.T) { span.Attributes().InsertDouble("keyDouble", 3245.6) span.Attributes().InsertBool("keyBool", true) span.Attributes().InsertString("keyExists", "present") + span.SetKind(pdata.SpanKindClient) assert.NotNil(t, span) resource := pdata.NewResource()