From f7622209cd395e9a1ca19803ba02cf220bb3aaae Mon Sep 17 00:00:00 2001 From: Poyzan <31743851+poyzannur@users.noreply.github.com> Date: Wed, 24 Jan 2024 15:41:34 +0000 Subject: [PATCH] [Fix] OR statements not being evaluated as part of nested line filters (#11735) **What this PR does / why we need it**: When nester line filters were being evaluated, the `OR` statements in right expressions were omitted and only `LineFilters` were returned. Resulting in only first value being returned. It can be reproduced in stringer unit test failing with, ``` Error Trace: /Users/poyzannur/workspace/loki/pkg/logql/syntax/ast_test.go:535 Error: Not equal: expected: "{app=\"foo\"} |= \"foo\" or \"bar\" |= \"baz\" or \"bal\"" actual : "{app=\"foo\"} |= \"foo\" or \"bar\" |= \"baz\"" ``` We now return the `OR` expression as part of nested line filters. Thanks a million to @ashwanthgoli for help with debugging, and extra unit test. **Which issue(s) this PR fixes**: Fixes https://github.com/grafana/support-escalations/issues/9042 **Special notes for your reviewer**: **Checklist** - [x] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [x] Tests updated - [ ] `CHANGELOG.md` updated - [ ] If the change is worth mentioning in the release notes, add `add-to-release-notes` label - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/setup/upgrade/_index.md` - [ ] For Helm chart changes bump the Helm chart version in `production/helm/loki/Chart.yaml` and update `production/helm/loki/CHANGELOG.md` and `production/helm/loki/README.md`. [Example PR](https://github.com/grafana/loki/commit/d10549e3ece02120974929894ee333d07755d213) - [ ] If the change is deprecating or removing a configuration option, update the `deprecated-config.yaml` and `deleted-config.yaml` files respectively in the `tools/deprecated-config-checker` directory. [Example PR](https://github.com/grafana/loki/pull/10840/commits/0d4416a4b03739583349934b96f272fb4f685d15) --- pkg/logql/syntax/ast.go | 2 ++ pkg/logql/syntax/ast_test.go | 15 ++++++++++++++ pkg/logql/syntax/parser_test.go | 35 +++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/pkg/logql/syntax/ast.go b/pkg/logql/syntax/ast.go index 900802207c50..cea41f4d95c5 100644 --- a/pkg/logql/syntax/ast.go +++ b/pkg/logql/syntax/ast.go @@ -353,6 +353,8 @@ func newNestedLineFilterExpr(left *LineFilterExpr, right *LineFilterExpr) *LineF return &LineFilterExpr{ Left: left, LineFilter: right.LineFilter, + Or: right.Or, + IsOrChild: right.IsOrChild, } } diff --git a/pkg/logql/syntax/ast_test.go b/pkg/logql/syntax/ast_test.go index b0c20005b74a..ece470516eb4 100644 --- a/pkg/logql/syntax/ast_test.go +++ b/pkg/logql/syntax/ast_test.go @@ -383,6 +383,13 @@ func Test_FilterMatcher(t *testing.T) { }, []linecheck{{"foo", true}, {"bar", true}, {"none", false}}, }, + { + `{app="foo"} |= "foo" or "bar" |= "buzz" or "fizz"`, + []*labels.Matcher{ + mustNewMatcher(labels.MatchEqual, "app", "foo"), + }, + []linecheck{{"foo buzz", true}, {"bar fizz", true}, {"foo", false}, {"bar", false}, {"none", false}}, + }, { `{app="foo"} != "foo" or "bar"`, []*labels.Matcher{ @@ -496,6 +503,14 @@ func TestStringer(t *testing.T) { in: `{app="foo"} |~ "foo" or "bar" or "baz"`, out: `{app="foo"} |~ "foo" or "bar" or "baz"`, }, + { + in: `{app="foo"} |= "foo" or "bar" |= "buzz" or "fizz"`, + out: `{app="foo"} |= "foo" or "bar" |= "buzz" or "fizz"`, + }, + { + out: `{app="foo"} |= "foo" or "bar" |~ "buzz|fizz"`, + in: `{app="foo"} |= "foo" or "bar" |~ "buzz|fizz"`, + }, { in: `{app="foo"} |= ip("127.0.0.1") or "foo"`, out: `{app="foo"} |= ip("127.0.0.1") or "foo"`, diff --git a/pkg/logql/syntax/parser_test.go b/pkg/logql/syntax/parser_test.go index cd45b6ec74c1..7152d78adac1 100644 --- a/pkg/logql/syntax/parser_test.go +++ b/pkg/logql/syntax/parser_test.go @@ -3138,6 +3138,41 @@ var ParseTestCases = []struct { }, }, }, + { + in: `{app="foo"} |= "foo" or "bar" |= "buzz" or "fizz"`, + exp: &PipelineExpr{ + Left: newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "app", "foo")}), + MultiStages: MultiStageExpr{ + &LineFilterExpr{ + Left: newOrLineFilter( + &LineFilterExpr{ + LineFilter: LineFilter{ + Ty: labels.MatchEqual, + Match: "foo", + }, + }, + &LineFilterExpr{ + LineFilter: LineFilter{ + Ty: labels.MatchEqual, + Match: "bar", + }, + }), + LineFilter: LineFilter{ + Ty: labels.MatchEqual, + Match: "buzz", + }, + Or: &LineFilterExpr{ + LineFilter: LineFilter{ + Ty: labels.MatchEqual, + Match: "fizz", + }, + IsOrChild: true, + }, + IsOrChild: false, + }, + }, + }, + }, } func TestParse(t *testing.T) {