Skip to content

Commit 267d8a6

Browse files
chaudumDylanGuedes
authored andcommitted
Fix parsing of vector expression (#8448)
Signed-off-by: Christian Haudum <[email protected]> (cherry picked from commit 96d5227)
1 parent 89b659e commit 267d8a6

File tree

5 files changed

+90
-23
lines changed

5 files changed

+90
-23
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@
88

99
##### Fixes
1010

11+
* [7784](https://github.com/grafana/loki/pull/7784) **isodude**: Fix default values of connect addresses for compactor and querier workers to work with IPv6.
12+
* [7880](https://github.com/grafana/loki/pull/7880) **sandeepsukhani**: consider range and offset in queries while looking for schema config for query sharding.
13+
* [7937](https://github.com/grafana/loki/pull/7937) **ssncferreira**: Deprecate CLI flag `-ruler.wal-cleaer.period` and replace it with `-ruler.wal-cleaner.period`.
14+
* [7966](https://github.com/grafana/loki/pull/7966) **sandeepsukhani**: Fix query-frontend request load balancing when using k8s service.
15+
* [7988](https://github.com/grafana/loki/pull/7988) **ashwanthgoli** store: write overlapping chunks to multiple stores.
16+
* [7925](https://github.com/grafana/loki/pull/7925) **sandeepsukhani**: Fix bugs in logs results caching causing query-frontend to return logs outside of query window.
17+
* [8120](https://github.com/grafana/loki/pull/8120) **ashwanthgoli** fix panic on hitting /scheduler/ring when ring is disabled.
18+
* [8251](https://github.com/grafana/loki/pull/8251) **sandeepsukhani** index-store: fix indexing of chunks overlapping multiple schemas.
19+
* [8151](https://github.com/grafana/loki/pull/8151) **sandeepsukhani** fix log deletion with line filters.
20+
* [8448](https://github.com/grafana/loki/pull/8448) **chaudum**: Fix bug in LogQL parser that caused certain queries that contain a vector expression to fail.
21+
1122
##### Changes
1223

1324
#### Promtail

pkg/logql/syntax/ast.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1621,7 +1621,7 @@ func (e *VectorExpr) Value() (float64, error) {
16211621

16221622
func (e *VectorExpr) Selector() LogSelectorExpr { return e }
16231623
func (e *VectorExpr) HasFilter() bool { return false }
1624-
func (e *VectorExpr) Shardable() bool { return true }
1624+
func (e *VectorExpr) Shardable() bool { return false }
16251625
func (e *VectorExpr) Walk(f WalkFn) { f(e) }
16261626
func (e *VectorExpr) Pipeline() (log.Pipeline, error) { return log.NewNoopPipeline(), nil }
16271627
func (e *VectorExpr) Matchers() []*labels.Matcher { return nil }

pkg/logql/syntax/parser.go

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func (p *parser) Parse() (Expr, error) {
6565

6666
// ParseExpr parses a string and returns an Expr.
6767
func ParseExpr(input string) (Expr, error) {
68-
expr, err := parseExprWithoutValidation(input)
68+
expr, err := ParseExprWithoutValidation(input)
6969
if err != nil {
7070
return nil, err
7171
}
@@ -75,7 +75,7 @@ func ParseExpr(input string) (Expr, error) {
7575
return expr, nil
7676
}
7777

78-
func parseExprWithoutValidation(input string) (expr Expr, err error) {
78+
func ParseExprWithoutValidation(input string) (expr Expr, err error) {
7979
if len(input) >= maxInputSize {
8080
return nil, logqlmodel.NewParseError(fmt.Sprintf("input size too long (%d > %d)", len(input), maxInputSize), 0, 0)
8181
}
@@ -103,31 +103,20 @@ func parseExprWithoutValidation(input string) (expr Expr, err error) {
103103
func validateExpr(expr Expr) error {
104104
switch e := expr.(type) {
105105
case SampleExpr:
106-
err := validateSampleExpr(e)
107-
if err != nil {
108-
return err
109-
}
106+
return validateSampleExpr(e)
110107
case LogSelectorExpr:
111-
err := validateMatchers(e.Matchers())
112-
if err != nil {
113-
return err
114-
}
108+
return validateLogSelectorExpression(e)
115109
default:
116110
return logqlmodel.NewParseError(fmt.Sprintf("unexpected expression type: %v", e), 0, 0)
117111
}
118-
return nil
119112
}
120113

121114
// validateMatchers checks whether a query would touch all the streams in the query range or uses at least one matcher to select specific streams.
122115
func validateMatchers(matchers []*labels.Matcher) error {
123-
if len(matchers) == 0 {
124-
return nil
125-
}
126116
_, matchers = util.SplitFiltersAndMatchers(matchers)
127117
if len(matchers) == 0 {
128118
return logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0)
129119
}
130-
131120
return nil
132121
}
133122

@@ -166,21 +155,63 @@ func ParseSampleExpr(input string) (SampleExpr, error) {
166155
func validateSampleExpr(expr SampleExpr) error {
167156
switch e := expr.(type) {
168157
case *BinOpExpr:
158+
if e.err != nil {
159+
return e.err
160+
}
169161
if err := validateSampleExpr(e.SampleExpr); err != nil {
170162
return err
171163
}
172-
173164
return validateSampleExpr(e.RHS)
174-
case *LiteralExpr, *VectorExpr:
165+
case *LiteralExpr:
166+
if e.err != nil {
167+
return e.err
168+
}
169+
return nil
170+
case *VectorExpr:
171+
if e.err != nil {
172+
return e.err
173+
}
174+
return nil
175+
case *VectorAggregationExpr:
176+
if e.err != nil {
177+
return e.err
178+
}
179+
if e.Operation == OpTypeSort || e.Operation == OpTypeSortDesc {
180+
if err := validateSortGrouping(e.Grouping); err != nil {
181+
return err
182+
}
183+
}
184+
return validateSampleExpr(e.Left)
185+
default:
186+
selector, err := e.Selector()
187+
if err != nil {
188+
return err
189+
}
190+
return validateLogSelectorExpression(selector)
191+
}
192+
}
193+
194+
func validateLogSelectorExpression(expr LogSelectorExpr) error {
195+
switch e := expr.(type) {
196+
case *VectorExpr:
175197
return nil
176198
default:
177-
return validateMatchers(expr.Selector().Matchers())
199+
return validateMatchers(e.Matchers())
178200
}
179201
}
180202

203+
// validateSortGrouping prevent by|without groupings on sort operations.
204+
// This will keep compatibility with promql and allowing sort by (foo) doesn't make much sense anyway when sort orders by value instead of labels.
205+
func validateSortGrouping(grouping *Grouping) error {
206+
if grouping != nil && len(grouping.Groups) > 0 {
207+
return logqlmodel.NewParseError("sort and sort_desc doesn't allow grouping by ", 0, 0)
208+
}
209+
return nil
210+
}
211+
181212
// ParseLogSelector parses a log selector expression `{app="foo"} |= "filter"`
182213
func ParseLogSelector(input string, validate bool) (LogSelectorExpr, error) {
183-
expr, err := parseExprWithoutValidation(input)
214+
expr, err := ParseExprWithoutValidation(input)
184215
if err != nil {
185216
return nil, err
186217
}
@@ -202,7 +233,18 @@ func ParseLabels(lbs string) (labels.Labels, error) {
202233
if err != nil {
203234
return nil, err
204235
}
236+
// Sort labels to ensure functionally equivalent
237+
// inputs map to the same output
205238
sort.Sort(ls)
206239

240+
// Use the label builder to trim empty label values.
241+
// Empty label values are equivalent to absent labels
242+
// in Prometheus, but they unfortunately alter the
243+
// Hash values created. This can cause problems in Loki
244+
// if we can't rely on a set of labels to have a deterministic
245+
// hash value.
246+
// Therefore we must normalize early in the write path.
247+
// See https://github.com/grafana/loki/pull/7355
248+
// for more information
207249
return labels.NewBuilder(ls).Labels(nil), nil
208250
}

pkg/logql/syntax/parser_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2858,6 +2858,23 @@ func TestParse(t *testing.T) {
28582858
in: `vector(abc)`,
28592859
err: logqlmodel.NewParseError("syntax error: unexpected IDENTIFIER, expecting NUMBER", 1, 8),
28602860
},
2861+
{
2862+
in: `vector(1)`,
2863+
exp: &VectorExpr{Val: 1, err: nil},
2864+
},
2865+
{
2866+
in: `label_replace(vector(0), "foo", "bar", "", "")`,
2867+
exp: mustNewLabelReplaceExpr(&VectorExpr{Val: 0, err: nil}, "foo", "bar", "", ""),
2868+
},
2869+
{
2870+
in: `sum(vector(0))`,
2871+
exp: &VectorAggregationExpr{
2872+
Left: &VectorExpr{Val: 0, err: nil},
2873+
Grouping: &Grouping{},
2874+
Params: 0,
2875+
Operation: "sum",
2876+
},
2877+
},
28612878
{
28622879
in: `{app="foo"}
28632880
# |= "bar"

pkg/querier/queryrange/querysharding.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,6 @@ func (ast *astMapperware) Do(ctx context.Context, r queryrangebase.Request) (que
119119
}
120120

121121
mapper := logql.NewShardMapper(resolver, ast.metrics)
122-
if err != nil {
123-
return nil, err
124-
}
125122

126123
noop, parsed, err := mapper.Parse(r.GetQuery())
127124
if err != nil {

0 commit comments

Comments
 (0)