Skip to content

Commit

Permalink
move extract matcher to traceql
Browse files Browse the repository at this point in the history
Signed-off-by: Ruben Vargas <[email protected]>
  • Loading branch information
rubenvp8510 committed Nov 24, 2023
1 parent 3c7a174 commit f38cd98
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 30 deletions.
10 changes: 2 additions & 8 deletions modules/ingester/instance_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,10 +362,10 @@ func (i *instance) SearchTagValuesV2(ctx context.Context, req *tempopb.SearchTag
return nil, err
}

query := util.ExtractMatchers(req.Query)
query := traceql.ExtractMatchers(req.Query)

var searchBlock func(common.Searcher) error
if !i.autocompleteFilteringEnabled || isEmptyQuery(query) {
if !i.autocompleteFilteringEnabled || traceql.IsEmptyQuery(query) {
// If filtering is disabled or query is empty,
// we can use the more efficient SearchTagValuesV2 method.
searchBlock = func(s common.Searcher) error {
Expand Down Expand Up @@ -460,12 +460,6 @@ func (i *instance) SearchTagValuesV2(ctx context.Context, req *tempopb.SearchTag
return resp, nil
}

func isEmptyQuery(query string) bool {
return query == emptyQuery || len(query) == 0
}

const emptyQuery = "{}"

// includeBlock uses the provided time range to determine if the block should be included in the search.
func includeBlock(b *backend.BlockMeta, req *tempopb.SearchRequest) bool {
start := int64(req.Start)
Expand Down
6 changes: 4 additions & 2 deletions modules/ingester/instance_search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"testing"
"time"

"github.com/grafana/tempo/pkg/traceql"

"github.com/google/uuid"
"github.com/grafana/dskit/user"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -951,7 +953,7 @@ func TestExtractMatchers(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
assert.Equal(t, tc.expected, util.ExtractMatchers(tc.query))
assert.Equal(t, tc.expected, traceql.ExtractMatchers(tc.query))
})
}
}
Expand All @@ -970,7 +972,7 @@ func BenchmarkExtractMatchers(b *testing.B) {
for _, query := range queries {
b.Run(query, func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = util.ExtractMatchers(query)
_ = traceql.ExtractMatchers(query)
}
})
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
package util
package traceql

import (
"regexp"
"strings"
)

// TODO: Support spaces, quotes
// See: https://github.com/grafana/grafana/issues/77394

// Regex to extract matchers from a query string
// This regular expression matches a string that contains three groups separated by operators.
// The first group is a string of alphabetical characters, dots, and underscores.
// The first group matches one or more Unicode letters, digits, underscores, or periods. It essentially matches variable names or identifiers
// The second group is a comparison operator, which can be one of several possibilities, including =, >, <, and !=.
// The third group is one of several possible values: a string enclosed in double quotes,
// a number with an optional time unit (such as "ns", "ms", "s", "m", or "h"),
// a plain number, or the boolean values "true" or "false".
// The third group is one of several possible values:
// 1. A double-quoted string consisting of one or more Unicode characters, including letters, digits, punctuation, diacritical marks, and symbols,
// 2. A sequence of one or more digits, which can represent numeric values, possibly with units like 's', 'm', or 'h'.
// 3. The boolean values "true" or "false".
//
// Example: "http.status_code = 200" from the query "{ .http.status_code = 200 && .http.method = }"
var matchersRegexp = regexp.MustCompile(`[a-zA-Z._]+\s*[=|<=|>=|=~|!=|>|<|!~]\s*(?:"[a-zA-Z./_0-9-]+"|[0-9smh]+|true|false)`)
var matchersRegexp = regexp.MustCompile(`[\p{L}\p{N}._]+\s*[=|<=|>=|=~|!=|>|<|!~]\s*(?:"[\p{L}\p{N}\p{P}\p{M}\p{S}]+"|true|false|[a-z]+|[0-9smh]+)`)

// TODO: Merge into a single regular expression

// Regex to extract selectors from a query string
// This regular expression matches a string that contains a single spanset filter and no OR `||` conditions.
// Examples
//
// Query | Match
// Query | Match
//
// { .bar = "foo" } | Yes
// { .bar = "foo" && .foo = "bar" } | Yes
// { .bar = "foo" || .foo = "bar" } | No
// { .bar = "foo" } && { .foo = "bar" } | No
// { .bar = "foo" } || { .foo = "bar" } | No
var singleFilterRegexp = regexp.MustCompile(`^{[a-zA-Z._\s\-()/&=<>~!0-9"]*}$`)
var singleFilterRegexp = regexp.MustCompile(`^\{[^|{}]*[^|{}]}?$`)

const emptyQuery = "{}"

// ExtractMatchers extracts matchers from a query string and returns a string that can be parsed by the storage layer.
func ExtractMatchers(query string) string {
query = strings.TrimSpace(query)

if len(query) == 0 {
return "{}"
return emptyQuery
}

selector := singleFilterRegexp.FindString(query)
if len(selector) == 0 {
return "{}"
return emptyQuery
}

matchers := matchersRegexp.FindAllString(query, -1)
Expand All @@ -57,3 +64,7 @@ func ExtractMatchers(query string) string {

return q.String()
}

func IsEmptyQuery(query string) bool {
return query == emptyQuery || len(query) == 0
}
12 changes: 2 additions & 10 deletions tempodb/tempodb.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,6 @@ func (rw *readerWriter) SearchForValuesTagsV2(ctx context.Context, meta *backend
return nil, err
}

var tagValues []*tempopb.TagValue

valueCollector := util.NewDistinctValueCollector[tempopb.TagValue](0, func(v tempopb.TagValue) int { return len(v.Type) + len(v.Value) })

engine := traceql.NewEngine()
Expand All @@ -454,9 +452,9 @@ func (rw *readerWriter) SearchForValuesTagsV2(ctx context.Context, meta *backend
return nil, err
}

query := util.ExtractMatchers(req.Query)
query := traceql.ExtractMatchers(req.Query)

if len(query) > 0 {
if traceql.IsEmptyQuery(query) {
fetcher := traceql.NewAutocompleteFetcherWrapper(func(ctx context.Context, req traceql.AutocompleteRequest, cb traceql.AutocompleteCallback) error {
return block.FetchTagValues(ctx, req, cb, common.DefaultSearchOptions())
})
Expand All @@ -477,12 +475,6 @@ func (rw *readerWriter) SearchForValuesTagsV2(ctx context.Context, meta *backend
err := block.SearchTagValuesV2(ctx, tag, traceql.MakeCollectTagValueFunc(valueCollector.Collect), opts)
return nil, err
}

resp := &tempopb.SearchTagValuesV2Response{
TagValues: tagValues,
}

return resp, nil
}

func (rw *readerWriter) Fetch(ctx context.Context, meta *backend.BlockMeta, req traceql.FetchSpansRequest, opts common.SearchOptions) (traceql.FetchSpansResponse, error) {
Expand Down

0 comments on commit f38cd98

Please sign in to comment.