diff --git a/pkg/logql/log/pattern/ast.go b/pkg/logql/log/pattern/ast.go index f8309d1c480b1..b4cf8e813f968 100644 --- a/pkg/logql/log/pattern/ast.go +++ b/pkg/logql/log/pattern/ast.go @@ -19,19 +19,18 @@ func (e expr) validate() error { if !e.hasCapture() { return ErrNoCapture } - // if there is at least 2 node, verify that none are consecutive. - if len(e) >= 2 { - for i := 0; i < len(e); i = i + 2 { - if i+1 >= len(e) { - break - } - if _, ok := e[i].(capture); ok { - if _, ok := e[i+1].(capture); ok { - return fmt.Errorf("found consecutive capture: %w", ErrInvalidExpr) - } + // Consecutive captures are not allowed. + for i, n := range e { + if i+1 >= len(e) { + break + } + if _, ok := n.(capture); ok { + if _, ok := e[i+1].(capture); ok { + return fmt.Errorf("found consecutive capture '%s': %w", n.String()+e[i+1].String(), ErrInvalidExpr) } } } + caps := e.captures() uniq := map[string]struct{}{} for _, c := range caps { @@ -46,7 +45,7 @@ func (e expr) validate() error { func (e expr) captures() (captures []string) { for _, n := range e { if c, ok := n.(capture); ok && !c.isUnamed() { - captures = append(captures, c.String()) + captures = append(captures, c.Name()) } } return @@ -59,6 +58,10 @@ func (e expr) captureCount() (count int) { type capture string func (c capture) String() string { + return "<" + string(c) + ">" +} + +func (c capture) Name() string { return string(c) } diff --git a/pkg/logql/log/pattern/pattern_test.go b/pkg/logql/log/pattern/pattern_test.go index 6a0a760dd29fa..da0c6a180527f 100644 --- a/pkg/logql/log/pattern/pattern_test.go +++ b/pkg/logql/log/pattern/pattern_test.go @@ -150,9 +150,11 @@ func Test_Error(t *testing.T) { {"<_>", ErrNoCapture}, {"foo <_> bar <_>", ErrNoCapture}, {"foo bar buzz", ErrNoCapture}, - {"", fmt.Errorf("found consecutive capture: %w", ErrInvalidExpr)}, - {" f", fmt.Errorf("found consecutive capture: %w", ErrInvalidExpr)}, + {"", fmt.Errorf("found consecutive capture '': %w", ErrInvalidExpr)}, + {" f", fmt.Errorf("found consecutive capture '': %w", ErrInvalidExpr)}, {" f", fmt.Errorf("duplicate capture name (f): %w", ErrInvalidExpr)}, + {`f<_>`, fmt.Errorf("found consecutive capture '<_>': %w", ErrInvalidExpr)}, + {`f<_>`, fmt.Errorf("found consecutive capture '<_>': %w", ErrInvalidExpr)}, } { t.Run(tt.name, func(t *testing.T) { _, err := New(tt.name)