From cb9227fab52944c965c04661db2b6ea6dca7df98 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 abdefe5b28a5..40250ba7d563 100644 --- a/internal/coreinternal/processor/filterconfig/config.go +++ b/internal/coreinternal/processor/filterconfig/config.go @@ -118,8 +118,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 "attributes", "libraries", "span_kinds", "resources", "log_bodies" or "log_severity_texts" field must be specified`) +) + // ValidateForSpans validates properties for spans. func (mp *MatchProperties) ValidateForSpans() error { if len(mp.LogBodies) > 0 { @@ -131,8 +141,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 @@ -140,12 +150,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 && len(mp.LogBodies) == 0 && len(mp.LogSeverityTexts) == 0 { - return errors.New(`at least one of "attributes", "libraries", "resources", "log_bodies" or "log_severity_texts" field must be specified`) + if len(mp.Attributes) == 0 && len(mp.Libraries) == 0 && len(mp.Resources) == 0 && len(mp.LogBodies) == 0 && len(mp.LogSeverityTexts) == 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 a0ef3cf84b97..70f5968c255d 100644 --- a/internal/coreinternal/processor/filterspan/filterspan.go +++ b/internal/coreinternal/processor/filterspan/filterspan.go @@ -43,6 +43,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. @@ -76,10 +79,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 } @@ -124,6 +136,10 @@ func (mp *propertiesMatcher) MatchSpan(span ptrace.Span, resource pcommon.Resour 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 aec2ee298a83..fcef5dd2a9ec 100644 --- a/internal/coreinternal/processor/filterspan/filterspan_test.go +++ b/internal/coreinternal/processor/filterspan/filterspan_test.go @@ -43,14 +43,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", @@ -113,7 +113,6 @@ func TestSpan_Matching_False(t *testing.T) { Attributes: []filterconfig.Attribute{}, }, }, - { name: "service_name_doesnt_match_strict", properties: &filterconfig.MatchProperties{ @@ -144,6 +143,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 := ptrace.NewSpan() @@ -218,6 +234,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 := ptrace.NewSpan() @@ -227,6 +263,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 := pcommon.NewResource()