Skip to content

Commit 328ad6d

Browse files
Add regexp support to service name include/exclude filters (#522)
- Added regexp support to service name field in include/exclude filters of attributes processor. This makes it consistent with span name fields which already use regexp patterns. - Added match_type to make service name and span name matching explicit. Testing: added unit and E2E tests. Documentation: README modified as appropriate.
1 parent 47ccdff commit 328ad6d

File tree

9 files changed

+439
-138
lines changed

9 files changed

+439
-138
lines changed

processor/README.md

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,24 @@ attributes:
148148
# It is supported to have more than one specified, but all of the specified
149149
# conditions must evaluate to true for a match to occur.
150150
151-
# Services specify the list of service name to match against.
152-
# A match occurs if the span service name is in this list.
153-
# Note: This is an optional field.
154-
services: [<key1>, ..., <keyN>]
155-
# The span name must match "login.*" or "auth.*" pattern.
156-
span_names: ["login.*", "auth.*"]
151+
# match_type controls how items in "services" and "span_names" arrays are
152+
# interpreted. Possible values are "regexp" or "strict".
153+
# This is a required field.
154+
match_type: {strict, regexp}
155+
156+
# services specify an array of items to match the service name against.
157+
# A match occurs if the span service name matches at least of the items.
158+
# This is an optional field.
159+
services: [<item1>, ..., <itemN>]
160+
161+
# The span name must match at least one of the items.
162+
# This is an optional field.
163+
span_names: [<item1>, ..., <itemN>]
164+
157165
# Attributes specifies the list of attributes to match against.
158166
# All of these attributes must match exactly for a match to occur.
159-
# Note: This is an optional field.
167+
# Only match_type=strict is allowed if "attributes" are specified.
168+
# This is an optional field.
160169
attributes:
161170
# Key specifies the attribute to match against.
162171
- key: <key>

processor/attributesprocessor/attributes.go

Lines changed: 103 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ type attributesProcessor struct {
3737
// raw format from the configuration.
3838
type attributesConfig struct {
3939
actions []attributeAction
40-
include *matchingProperties
41-
exclude *matchingProperties
40+
include matchingProperties
41+
exclude matchingProperties
4242
}
4343

4444
type attributeAction struct {
@@ -52,17 +52,38 @@ type attributeAction struct {
5252
AttributeValue *tracepb.AttributeValue
5353
}
5454

55-
// matchingProperties stores the MatchProperties config in a format that simplifies
56-
// and makes property checking faster.
57-
type matchingProperties struct {
58-
// The list of service names is stored in a map for quick lookup.
59-
Services map[string]bool
55+
// matchingProperties is an interface that allows matching a span against a configuration
56+
// of a match.
57+
type matchingProperties interface {
58+
matchSpan(span *tracepb.Span, serviceName string) bool
59+
}
60+
61+
type matchAttributes []matchAttribute
62+
63+
// strictMatchingProperties allows matching a span against a "strict" match type
64+
// configuration.
65+
type strictMatchingProperties struct {
66+
// Service names to compare to.
67+
Services []string
68+
69+
// Span names to compare to.
70+
SpanNames []string
71+
72+
// The attribute values are stored in the internal format.
73+
Attributes matchAttributes
74+
}
75+
76+
// strictMatchingProperties allows matching a span against a "regexp" match type
77+
// configuration.
78+
type regexpMatchingProperties struct {
79+
// Precompiled service name regexp-es.
80+
Services []*regexp.Regexp
6081

6182
// Precompiled span name regexp-es.
6283
SpanNames []*regexp.Regexp
6384

6485
// The attribute values are stored in the internal format.
65-
Attributes []matchAttribute
86+
Attributes matchAttributes
6687
}
6788

6889
// matchAttribute is a attribute key/value pair to match to.
@@ -187,33 +208,86 @@ func (a *attributesProcessor) skipSpan(span *tracepb.Span, serviceName string) b
187208

188209
if a.config.include != nil {
189210
// A false returned in this case means the span should not be processed.
190-
if include := matchSpanToProperties(*a.config.include, span, serviceName); !include {
211+
if include := a.config.include.matchSpan(span, serviceName); !include {
191212
return true
192213
}
193214
}
194215

195216
if a.config.exclude != nil {
196217
// A true returned in this case means the span should not be processed.
197-
if exclude := matchSpanToProperties(*a.config.exclude, span, serviceName); exclude {
218+
if exclude := a.config.exclude.matchSpan(span, serviceName); exclude {
198219
return true
199220
}
200221
}
201222

202223
return false
203224
}
204225

205-
// matchProperties matches a span and service to a set of properties.
206-
// There are two sets of properties to match against.
207-
// The service name is checked first, if specified. The attributes are checked
208-
// afterwards, if specified.
209-
// At least one of services or attributes must be specified. It is supported
210-
// to have both specified, but both `services` and `attributes` must evaluate
226+
// matchSpan matches a span and service to a set of properties.
227+
// There are 3 sets of properties to match against.
228+
// The service name is checked first, if specified. Then span names are matched, if specified.
229+
// The attributes are checked last, if specified.
230+
// At least one of services, span names or attributes must be specified. It is supported
231+
// to have more than one of these specified, and all specified must evaluate
211232
// to true for a match to occur.
212-
func matchSpanToProperties(mp matchingProperties, span *tracepb.Span, serviceName string) bool {
233+
func (mp *strictMatchingProperties) matchSpan(span *tracepb.Span, serviceName string) bool {
213234

214-
if len(mp.Services) != 0 {
215-
// Services condition is specified. Check if the service is one the specified.
216-
if serviceFound := mp.Services[serviceName]; !serviceFound {
235+
if len(mp.Services) > 0 {
236+
// Verify service name matches at least one of the items.
237+
matched := false
238+
for _, item := range mp.Services {
239+
if item == serviceName {
240+
matched = true
241+
break
242+
}
243+
}
244+
if !matched {
245+
return false
246+
}
247+
}
248+
249+
if len(mp.SpanNames) > 0 {
250+
// SpanNames condition is specified. Check if span name matches the condition.
251+
var spanName string
252+
if span.Name != nil {
253+
spanName = span.Name.Value
254+
}
255+
// Verify span name matches at least one of the items.
256+
matched := false
257+
for _, item := range mp.SpanNames {
258+
if item == spanName {
259+
matched = true
260+
break
261+
}
262+
}
263+
if !matched {
264+
return false
265+
}
266+
}
267+
268+
// Service name and span name matched. Now match attributes.
269+
return mp.Attributes.match(span)
270+
}
271+
272+
// matchSpan matches a span and service to a set of properties.
273+
// There are 3 sets of properties to match against.
274+
// The service name is checked first, if specified. Then span names are matched, if specified.
275+
// The attributes are checked last, if specified.
276+
// At least one of services, span names or attributes must be specified. It is supported
277+
// to have more than one of these specified, and all specified must evaluate
278+
// to true for a match to occur.
279+
func (mp *regexpMatchingProperties) matchSpan(span *tracepb.Span, serviceName string) bool {
280+
281+
if len(mp.Services) > 0 {
282+
// Verify service name matches at least one of the regexp patterns.
283+
matched := false
284+
for _, re := range mp.Services {
285+
if re.MatchString(serviceName) {
286+
matched = true
287+
break
288+
}
289+
}
290+
if !matched {
217291
return false
218292
}
219293
}
@@ -237,19 +311,25 @@ func matchSpanToProperties(mp matchingProperties, span *tracepb.Span, serviceNam
237311
}
238312
}
239313

314+
// Service name and span name matched. Now match attributes.
315+
return mp.Attributes.match(span)
316+
}
317+
318+
// match attributes specification against a span.
319+
func (ma matchAttributes) match(span *tracepb.Span) bool {
240320
// If there are no attributes to match against, the span matches.
241-
if len(mp.Attributes) == 0 {
321+
if len(ma) == 0 {
242322
return true
243323
}
244324

245325
// At this point, it is expected of the span to have attributes because of
246-
// len (mp.Attributes) != 0. For spans with no attributes, it does not match.
326+
// len(ma) != 0. This means for spans with no attributes, it does not match.
247327
if span.Attributes == nil || len(span.Attributes.AttributeMap) == 0 {
248328
return false
249329
}
250330

251331
// Check that all expected properties are set.
252-
for _, property := range mp.Attributes {
332+
for _, property := range ma {
253333
val, exist := span.Attributes.AttributeMap[property.Key]
254334
if !exist {
255335
return false
@@ -283,7 +363,5 @@ func matchSpanToProperties(mp matchingProperties, span *tracepb.Span, serviceNam
283363
return false
284364
}
285365
}
286-
287-
// All properties have been satisfied so the span does match.
288366
return true
289367
}

0 commit comments

Comments
 (0)