Skip to content

Commit

Permalink
match spans on instrumentation library
Browse files Browse the repository at this point in the history
  • Loading branch information
zeitlinger committed Jul 28, 2020
1 parent 239fca8 commit bdf7a77
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 28 deletions.
15 changes: 15 additions & 0 deletions internal/processor/filterspan/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ type MatchProperties struct {
// This is an optional field.
Resources []Attribute `mapstructure:"resource"`

Libraries []InstrumentationLibrary `mapstructure:"libraries"`

// SpanNames specify the list of items to match span name against.
// A match occurs if the span name matches at least one item in this list.
// This is an optional field.
Expand All @@ -102,3 +104,16 @@ type Attribute struct {
// If it is not set, any value will match.
Value interface{} `mapstructure:"value"`
}

type InstrumentationLibrary struct {
Name string `mapstructure:"name"`
// version match
// expected actual match
// nil <blank> yes
// nil 1 yes
// <blank> <blank> yes
// <blank> 1 no
// 1 <blank> no
// 1 1 yes
Version *string `mapstructure:"version"`
}
52 changes: 44 additions & 8 deletions internal/processor/filterspan/filterspan.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var (
// TODO Add processor type invoking the NewMatcher in error text.
errAtLeastOneMatchFieldNeeded = errors.New(
`error creating processor. At least one ` +
`of "services", "span_names" or "attributes" field must be specified"`)
`of "services", "span_names", "libraries", "attributes" or "resources" field must be specified"`)

errUnexpectedAttributeType = errors.New("unexpected attribute type")
)
Expand All @@ -39,7 +39,7 @@ var (
// Matcher is an interface that allows matching a span against a configuration
// of a match.
type Matcher interface {
MatchSpan(span pdata.Span, resource pdata.Resource) bool
MatchSpan(span pdata.Span, resource pdata.Resource, library pdata.InstrumentationLibrary) bool
}

// propertiesMatcher allows matching a span against various span properties.
Expand All @@ -50,12 +50,20 @@ type propertiesMatcher struct {
// Span names to compare to.
nameFilters filterset.FilterSet

// Instrumentation libraries to compare against
Libraries []instrumentationLibraryMatcher

// The attribute values are stored in the internal format.
Attributes attributesMatcher

Resources attributesMatcher
}

type instrumentationLibraryMatcher struct {
Name filterset.FilterSet
Version filterset.FilterSet
}

type attributesMatcher []attributeMatcher

// attributeMatcher is a attribute key/value pair to match to.
Expand All @@ -72,12 +80,30 @@ func NewMatcher(mp *MatchProperties) (Matcher, error) {
return nil, nil
}

if len(mp.Services) == 0 && len(mp.SpanNames) == 0 && len(mp.Attributes) == 0 && len(mp.Resources) == 0 {
if len(mp.Libraries) == 0 && len(mp.Services) == 0 && len(mp.SpanNames) == 0 && len(mp.Attributes) == 0 && len(mp.Resources) == 0 {
return nil, errAtLeastOneMatchFieldNeeded
}

var err error
var lm []instrumentationLibraryMatcher
for _, library := range mp.Libraries {
name, err := filterset.CreateFilterSet([]string{library.Name}, &mp.Config)
if err != nil {
return nil, fmt.Errorf("error creating library name filters: %v", err)
}

var version filterset.FilterSet
if library.Version != nil {
filter, err := filterset.CreateFilterSet([]string{*library.Version}, &mp.Config)
if err != nil {
return nil, fmt.Errorf("error creating library version filters: %v", err)
}
version = filter
}

lm = append(lm, instrumentationLibraryMatcher{Name: name, Version: version})
}

var err error
var am attributesMatcher
if len(mp.Attributes) > 0 {
am, err = newAttributesMatcher(mp.Config, mp.Attributes)
Expand Down Expand Up @@ -113,6 +139,7 @@ func NewMatcher(mp *MatchProperties) (Matcher, error) {
return &propertiesMatcher{
serviceFilters: serviceFS,
nameFilters: nameFS,
Libraries: lm,
Attributes: am,
Resources: rm,
}, nil
Expand Down Expand Up @@ -165,17 +192,17 @@ func newAttributesMatcher(config filterset.Config, attributes []Attribute) (attr
// The logic determining if a span should be processed is set
// in the attribute configuration with the include and exclude settings.
// Include properties are checked before exclude settings are checked.
func SkipSpan(include Matcher, exclude Matcher, span pdata.Span, resource pdata.Resource) bool {
func SkipSpan(include Matcher, exclude Matcher, span pdata.Span, resource pdata.Resource, library pdata.InstrumentationLibrary) bool {
if include != nil {
// A false returned in this case means the span should not be processed.
if i := include.MatchSpan(span, resource); !i {
if i := include.MatchSpan(span, resource, library); !i {
return true
}
}

if exclude != nil {
// A true returned in this case means the span should not be processed.
if e := exclude.MatchSpan(span, resource); e {
if e := exclude.MatchSpan(span, resource, library); e {
return true
}
}
Expand All @@ -190,7 +217,7 @@ func SkipSpan(include Matcher, exclude Matcher, span pdata.Span, resource pdata.
// At least one of services, span names or attributes must be specified. It is supported
// to have more than one of these specified, and all specified must evaluate
// to true for a match to occur.
func (mp *propertiesMatcher) MatchSpan(span pdata.Span, resource pdata.Resource) bool {
func (mp *propertiesMatcher) MatchSpan(span pdata.Span, resource pdata.Resource, library pdata.InstrumentationLibrary) bool {
// If a set of properties was not in the mp, all spans are considered to match on that property
if mp.serviceFilters != nil {
serviceName := serviceNameForResource(resource)
Expand All @@ -203,6 +230,15 @@ func (mp *propertiesMatcher) MatchSpan(span pdata.Span, resource pdata.Resource)
return false
}

for _, matcher := range mp.Libraries {
if !matcher.Name.Matches(library.Name()) {
return false
}
if matcher.Version != nil && !matcher.Version.Matches(library.Version()) {
return false
}
}

if mp.Resources != nil && !mp.Resources.match(span) {
return false
}
Expand Down
50 changes: 32 additions & 18 deletions internal/processor/filterspan/filterspan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ func TestSpan_Matching_False(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, matcher)

assert.False(t, matcher.MatchSpan(span, resource("wrongSvc")))
assert.False(t, matcher.MatchSpan(span, resource("wrongSvc"), pdata.NewInstrumentationLibrary()))
})
}
}
Expand Down Expand Up @@ -296,7 +296,7 @@ func TestSpan_MatchingCornerCases(t *testing.T) {

emptySpan := pdata.NewSpan()
emptySpan.InitEmpty()
assert.False(t, mp.MatchSpan(emptySpan, resource("svcA")))
assert.False(t, mp.MatchSpan(emptySpan, resource("svcA"), pdata.NewInstrumentationLibrary()))
}

func TestSpan_MissingServiceName(t *testing.T) {
Expand All @@ -311,36 +311,49 @@ func TestSpan_MissingServiceName(t *testing.T) {

emptySpan := pdata.NewSpan()
emptySpan.InitEmpty()
assert.False(t, mp.MatchSpan(emptySpan, resource("")))
assert.False(t, mp.MatchSpan(emptySpan, resource(""), pdata.NewInstrumentationLibrary()))
}

func TestSpan_Matching_True(t *testing.T) {
ver := "v.*"

testcases := []struct {
name string
properties *MatchProperties
}{
{
name: "service_name_match_regexp",
properties: &MatchProperties{
Config: *createConfig(filterset.Regexp),
Services: []string{"svcA"},
Attributes: []Attribute{},
Config: *createConfig(filterset.Regexp),
Services: []string{"svcA"},
},
},
{
name: "service_name_match_strict",
properties: &MatchProperties{
Config: *createConfig(filterset.Strict),
Services: []string{"svcA"},
Attributes: []Attribute{},
Config: *createConfig(filterset.Strict),
Services: []string{"svcA"},
},
},
{
name: "library_match",
properties: &MatchProperties{
Config: *createConfig(filterset.Regexp),
Libraries: []InstrumentationLibrary{{Name: "li.*"}},
},
},
{
name: "library_match_with_version",
properties: &MatchProperties{
Config: *createConfig(filterset.Regexp),
Libraries: []InstrumentationLibrary{{Name: "li.*", Version: &ver}},
},
},
{
name: "span_name_match",
properties: &MatchProperties{
Config: *createConfig(filterset.Regexp),
SpanNames: []string{"span.*"},
Attributes: []Attribute{},
Config: *createConfig(filterset.Regexp),
SpanNames: []string{"span.*"},
},
},
{
Expand All @@ -353,14 +366,12 @@ func TestSpan_Matching_True(t *testing.T) {
"yet another?pattern",
"regularstring",
},
Attributes: []Attribute{},
},
},
{
name: "attribute_exact_value_match",
properties: &MatchProperties{
Config: *createConfig(filterset.Strict),
Services: []string{},
Config: *createConfig(filterset.Strict),
Attributes: []Attribute{
{
Key: "keyString",
Expand Down Expand Up @@ -408,8 +419,7 @@ func TestSpan_Matching_True(t *testing.T) {
{
name: "resource_exact_value_match",
properties: &MatchProperties{
Config: *createConfig(filterset.Strict),
Services: []string{},
Config: *createConfig(filterset.Strict),
Resources: []Attribute{
{
Key: "keyString",
Expand Down Expand Up @@ -473,9 +483,13 @@ func TestSpan_Matching_True(t *testing.T) {
mp, err := NewMatcher(tc.properties)
assert.Nil(t, err)
assert.NotNil(t, mp)
library := pdata.NewInstrumentationLibrary()
library.InitEmpty()
library.SetName("lib")
library.SetVersion("ver")

assert.NotNil(t, span)
assert.True(t, mp.MatchSpan(span, resource))
assert.True(t, mp.MatchSpan(span, resource, library))
})
}
}
Expand Down
3 changes: 2 additions & 1 deletion processor/attributesprocessor/attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,15 @@ func (a *attributesProcessor) ProcessTraces(_ context.Context, td pdata.Traces)
continue
}
spans := ils.Spans()
library := ils.InstrumentationLibrary()
for k := 0; k < spans.Len(); k++ {
span := spans.At(k)
if span.IsNil() {
// Do not create empty spans just to add attributes
continue
}

if filterspan.SkipSpan(a.include, a.exclude, span, rs.Resource()) {
if filterspan.SkipSpan(a.include, a.exclude, span, rs.Resource(), library) {
continue
}

Expand Down
3 changes: 2 additions & 1 deletion processor/spanprocessor/span.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,14 @@ func (sp *spanProcessor) ProcessTraces(_ context.Context, td pdata.Traces) (pdat
continue
}
spans := ils.Spans()
library := ils.InstrumentationLibrary()
for k := 0; k < spans.Len(); k++ {
s := spans.At(k)
if s.IsNil() {
continue
}

if filterspan.SkipSpan(sp.include, sp.exclude, s, rs.Resource()) {
if filterspan.SkipSpan(sp.include, sp.exclude, s, rs.Resource(), library) {
continue
}
sp.processFromAttributes(s)
Expand Down

0 comments on commit bdf7a77

Please sign in to comment.