diff --git a/pkg/logql/log/label_filter.go b/pkg/logql/log/label_filter.go index 1fda5430b7..279669e5a7 100644 --- a/pkg/logql/log/label_filter.go +++ b/pkg/logql/log/label_filter.go @@ -368,6 +368,16 @@ type lineFilterLabelFilter struct { filter Filterer } +// overrides the matcher.String() function in case there is a regexpFilter +func (s *lineFilterLabelFilter) String() string { + if unwrappedFilter, ok := s.filter.(regexpFilter); ok { + rStr := unwrappedFilter.String() + str := fmt.Sprintf(`%s%s"%s"`, s.Matcher.Name, s.Matcher.Type, rStr) + return str + } + return s.Matcher.String() +} + func (s *lineFilterLabelFilter) Process(_ int64, line []byte, lbs *LabelsBuilder) ([]byte, bool) { v := labelValue(s.Name, lbs) return line, s.filter.Filter(unsafeGetBytes(v)) diff --git a/pkg/logql/syntax/parser_test.go b/pkg/logql/syntax/parser_test.go index 819fdd1ca1..f5a21c21f8 100644 --- a/pkg/logql/syntax/parser_test.go +++ b/pkg/logql/syntax/parser_test.go @@ -3465,3 +3465,13 @@ func TestNoOpLabelToString(t *testing.T) { require.NoError(t, err) require.Len(t, stages, 0) } + +// Tests that the regex part of expr doesn't get doubly escaped when we call expr.String() +func TestParseSampleExpr_String(t *testing.T) { + query := `sum(rate({cluster="beep", namespace="boop"} | msg=~` + "`" + `.*?(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS) /loki/api/(?i)(\d+[a-z]|[a-z]+\d)\w*/query_range` + "`" + `[1d]))` + expr, err := ParseSampleExpr(query) + require.NoError(t, err) + // need to change some backticks to " in order for query to be exactly equal to expr.String(), otherwise it's the same query + expected := `sum(rate({cluster="beep", namespace="boop"} | msg=~".*?(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS) /loki/api/(?i)(\d+[a-z]|[a-z]+\d)\w*/query_range"[1d]))` + require.Equal(t, expected, expr.String()) +}