diff --git a/ddtrace/tracer/util.go b/ddtrace/tracer/util.go index 116d0aef4d..51684db537 100644 --- a/ddtrace/tracer/util.go +++ b/ddtrace/tracer/util.go @@ -8,6 +8,7 @@ package tracer import ( "encoding/base64" "fmt" + "regexp" "strconv" "strings" @@ -129,3 +130,15 @@ var b64 = base64.StdEncoding.WithPadding(base64.NoPadding) func b64Encode(s string) string { return b64.EncodeToString([]byte(s)) } + +// globMatch compiles pattern string into glob format, i.e. regular expressions with only '?' +// and '*' treated as regex metacharacters. +func globMatch(pattern string) (*regexp.Regexp, error) { + // escaping regex characters + pattern = regexp.QuoteMeta(pattern) + // replacing '?' and '*' with regex characters + pattern = strings.Replace(pattern, "\\?", ".", -1) + pattern = strings.Replace(pattern, "\\*", ".*", -1) + //pattern must match an entire string + return regexp.Compile(fmt.Sprintf("^%s$", pattern)) +} diff --git a/ddtrace/tracer/util_test.go b/ddtrace/tracer/util_test.go index 42cc0a5f39..7325b7a29c 100644 --- a/ddtrace/tracer/util_test.go +++ b/ddtrace/tracer/util_test.go @@ -115,3 +115,54 @@ func TestParsePropagatableTraceTags(t *testing.T) { }) } } + +func TestGlobMatch(t *testing.T) { + for i, tt := range []struct { + pattern string + input string + shouldMatch bool + }{ + // pattern with * + {"test*", "test", true}, + {"test*", "test-case", true}, + {"test*", "a-test", false}, + {"*test", "a-test", true}, + {"a*case", "acase", true}, + {"a*case", "a-test-case", true}, + {"a*test*case", "a-test-case", true}, + {"a*test*case", "atestcase", true}, + {"a*test*case", "abadcase", false}, + // pattern with ? + {"test?", "test", false}, + {"test?", "test-case", false}, + {"test?", "a-test", false}, + {"?test", "a-test", false}, + {"a?case", "acase", false}, + {"a?case", "a-case", true}, + {"a?test?case", "a-test-case", true}, + {"a?test?case", "a-test--case", false}, + // pattern with ? and * + {"?test*", "atest", true}, + {"?test*", "atestcase", true}, + {"?test*", "testcase", false}, + {"?test*", "testcase", false}, + {"test*case", "testcase", true}, + {"a?test*", "a-test-case", true}, + {"a?test*", "atestcase", false}, + {"a*test?", "a-test-", true}, + {"a*test?", "atestcase", false}, + {"a*test?case", "a--test-case", true}, + {"a*test?case", "a--test--case", false}, + {"a?test*case", "a-testing--case", true}, + {"the?test*case", "the-test-cases", false}, + } { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + rg, _ := globMatch(tt.pattern) + if tt.shouldMatch { + assert.Regexp(t, rg, tt.input) + } else { + assert.NotRegexp(t, rg, tt.input) + } + }) + } +}