diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c34084b6..0f3f2699 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,10 +31,7 @@ jobs: - name: Check for local changes run: git diff --exit-code - # Codecov reporting is unreliable. - # Re-run report 3 times to have a better - # chance of success. - - name: Report code coverage (1) + - name: Report code coverage uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -43,19 +40,3 @@ jobs: handle_no_reports_found: true continue-on-error: true - - name: Report code coverage (2) - uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: ./.cover/coverage.out - fail_ci_if_error: true - handle_no_reports_found: true - continue-on-error: true - - - name: Report code coverage (3) - uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: ./.cover/coverage.out - fail_ci_if_error: true - handle_no_reports_found: true diff --git a/docs/changelog.md b/docs/changelog.md index 923ad360..b00b979f 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -7,6 +7,13 @@ - Added `names` option to the `parser` block, which controls how does Prometheus validates label names. +### Fixed + +- Improved the logic of [promql/series](checks/promql/series.md) check to skip checks on some selectors + which absence might be expected. For example using `foo unless bar` will now only have `foo` + tested while `bar` is ignored by this check. This is because the query implies that `bar` + might be present or missing and depending on that `foo` is evaluated. + ## v0.70.0 ### Added diff --git a/docs/checks/promql/series.md b/docs/checks/promql/series.md index 34336b4b..66bdb489 100644 --- a/docs/checks/promql/series.md +++ b/docs/checks/promql/series.md @@ -21,6 +21,10 @@ to determine why, by checking if: - `my_metric` has any series with `foo` label - `my_metric` has any series matching `foo="bar"` +## Ignored cases + +### vector() fallback + Metrics that are wrapped in `... or vector(0)` won't be checked, since the intention of adding `or vector(0)` is to provide a fallback value when there are no matching time series. @@ -31,6 +35,17 @@ Example: expr: sum(my_metric or vector(0)) > 1 ``` +### foo unless bar + +In a query using `foo unless bar` only `foo` selector will be tested, since +this query implies that the presence of `bar` is not guaranteed. +`bar` is only tested for being present and so it's likely that it might be missing. + +Note that using `foo unless bar > 5` doesn't follow the same pattern and will have +both `foo` and `bar` tested by this check +Having `bar > 5` means it's assumed to be always present as we're testing it's value, +rather than it's existence. + ## Common problems If you see this check complaining about some metric it's might due to a number diff --git a/internal/checks/alerts_template.go b/internal/checks/alerts_template.go index 6900f0a0..9efdb8da 100644 --- a/internal/checks/alerts_template.go +++ b/internal/checks/alerts_template.go @@ -443,7 +443,7 @@ func checkQueryLabels(query, labelName, labelValue string, src []utils.Source) ( if s.IsDead { continue } - if s.FixedLabels && !slices.Contains(s.IncludedLabels, v[1]) { + if s.FixedLabels && !slices.Contains(s.IncludedLabels, v[1]) && !slices.Contains(s.GuaranteedLabels, v[1]) { problems = append(problems, textForProblem(query, v[1], "", s, Bug)) goto NEXT } diff --git a/internal/checks/promql_rate.go b/internal/checks/promql_rate.go index 2f146acf..b2f1ec5b 100644 --- a/internal/checks/promql_rate.go +++ b/internal/checks/promql_rate.go @@ -157,8 +157,8 @@ func (c RateCheck) checkNode(ctx context.Context, node *parser.PromQLNode, entri if src.Type != utils.AggregateSource { continue } - for _, vs := range src.Selectors { - metadata, err := c.prom.Metadata(ctx, vs.Name) + if src.Selector != nil { + metadata, err := c.prom.Metadata(ctx, src.Selector.Name) if err != nil { if errors.Is(err, promapi.ErrUnsupported) { continue @@ -186,7 +186,7 @@ func (c RateCheck) checkNode(ctx context.Context, node *parser.PromQLNode, entri } problems = append(problems, exprProblem{ text: fmt.Sprintf("`rate(%s(counter))` chain detected, `%s` is called here on results of `%s(%s)`.", - src.Operation, node.Expr, src.Operation, vs), + src.Operation, node.Expr, src.Operation, src.Selector), details: fmt.Sprintf( "You can only calculate `rate()` directly from a counter metric. "+ "Calling `rate()` on `%s()` results will return bogus results because `%s()` will hide information on when each counter resets. "+ diff --git a/internal/checks/promql_series.go b/internal/checks/promql_series.go index afa13973..8cc2ff4e 100644 --- a/internal/checks/promql_series.go +++ b/internal/checks/promql_series.go @@ -143,7 +143,7 @@ func (c SeriesCheck) Check(ctx context.Context, _ discovery.Path, rule parser.Ru selectors := utils.HasVectorSelector(expr.Query) done := map[string]bool{} - for _, selector := range getNonFallbackSelectors(expr.Query) { + for _, selector := range getNonFallbackSelectors(expr) { if _, ok := done[selector.String()]; ok { continue } @@ -186,7 +186,7 @@ func (c SeriesCheck) Check(ctx context.Context, _ discovery.Path, rule parser.Ru if arEntry != nil { slog.Debug( "Metric is provided by alerting rule", - slog.String("selector", (&selector).String()), + slog.String("selector", selector.String()), slog.String("path", arEntry.Path.Name), ) } else { @@ -218,14 +218,14 @@ func (c SeriesCheck) Check(ctx context.Context, _ discovery.Path, rule parser.Ru } // 1. If foo{bar, baz} is there -> GOOD - slog.Debug("Checking if selector returns anything", slog.String("check", c.Reporter()), slog.String("selector", (&selector).String())) + slog.Debug("Checking if selector returns anything", slog.String("check", c.Reporter()), slog.String("selector", selector.String())) count, err := c.instantSeriesCount(ctx, fmt.Sprintf("count(%s)", selector.String())) if err != nil { problems = append(problems, c.queryProblem(err, expr)) continue } if count > 0 { - slog.Debug("Found series, skipping further checks", slog.String("check", c.Reporter()), slog.String("selector", (&selector).String())) + slog.Debug("Found series, skipping further checks", slog.String("check", c.Reporter()), slog.String("selector", selector.String())) continue } @@ -376,7 +376,7 @@ func (c SeriesCheck) Check(ctx context.Context, _ discovery.Path, rule parser.Ru slog.Debug( "Series disappeared from prometheus but for less then configured min-age", slog.String("check", c.Reporter()), - slog.String("selector", (&selector).String()), + slog.String("selector", selector.String()), slog.String("min-age", output.HumanizeDuration(minAge)), slog.String("last-seen", sinceDesc(newest(trs.Series.Ranges))), ) @@ -444,7 +444,7 @@ func (c SeriesCheck) Check(ctx context.Context, _ discovery.Path, rule parser.Ru Severity: severity, }) slog.Debug("No historical series matching filter used in the query", - slog.String("check", c.Reporter()), slog.String("selector", (&selector).String()), slog.String("matcher", lm.String())) + slog.String("check", c.Reporter()), slog.String("selector", selector.String()), slog.String("matcher", lm.String())) continue } @@ -482,7 +482,7 @@ func (c SeriesCheck) Check(ctx context.Context, _ discovery.Path, rule parser.Ru slog.Debug( "Series disappeared from prometheus but for less then configured min-age", slog.String("check", c.Reporter()), - slog.String("selector", (&selector).String()), + slog.String("selector", selector.String()), slog.String("min-age", output.HumanizeDuration(minAge)), slog.String("last-seen", sinceDesc(newest(trsLabel.Series.Ranges))), ) @@ -507,7 +507,7 @@ func (c SeriesCheck) Check(ctx context.Context, _ discovery.Path, rule parser.Ru slog.Debug( "Series matching filter disappeared from prometheus", slog.String("check", c.Reporter()), - slog.String("selector", (&selector).String()), + slog.String("selector", selector.String()), slog.String("matcher", lm.String()), ) continue @@ -528,7 +528,7 @@ func (c SeriesCheck) Check(ctx context.Context, _ discovery.Path, rule parser.Ru slog.Debug( "Series matching filter are only sometimes present", slog.String("check", c.Reporter()), - slog.String("selector", (&selector).String()), + slog.String("selector", selector.String()), slog.String("matcher", lm.String()), ) } @@ -686,7 +686,7 @@ func (c SeriesCheck) instantSeriesCount(ctx context.Context, query string) (int, return series, nil } -func (c SeriesCheck) getMinAge(rule parser.Rule, selector promParser.VectorSelector) (minAge time.Duration, problems []Problem) { +func (c SeriesCheck) getMinAge(rule parser.Rule, selector *promParser.VectorSelector) (minAge time.Duration, problems []Problem) { minAge = time.Hour * 2 for _, ruleSet := range comments.Only[comments.RuleSet](rule.Comments, comments.RuleSetType) { matcher, key, value := parseRuleSet(ruleSet.Value) @@ -716,7 +716,7 @@ func (c SeriesCheck) getMinAge(rule parser.Rule, selector promParser.VectorSelec return minAge, problems } -func (c SeriesCheck) isLabelValueIgnored(settings *PromqlSeriesSettings, rule parser.Rule, selector promParser.VectorSelector, labelName string) bool { +func (c SeriesCheck) isLabelValueIgnored(settings *PromqlSeriesSettings, rule parser.Rule, selector *promParser.VectorSelector, labelName string) bool { for matcher, names := range settings.IgnoreLabelsValue { isMatch, _ := matchSelectorToMetric(selector, matcher) if !isMatch { @@ -739,7 +739,7 @@ func (c SeriesCheck) isLabelValueIgnored(settings *PromqlSeriesSettings, rule pa } } if labelName == value { - slog.Debug("Label check disabled by comment", slog.String("selector", (&selector).String()), slog.String("label", labelName)) + slog.Debug("Label check disabled by comment", slog.String("selector", selector.String()), slog.String("label", labelName)) return true } } @@ -760,36 +760,51 @@ func (c SeriesCheck) textAndSeverity(settings *PromqlSeriesSettings, name, text return text, s } -func getNonFallbackSelectors(n *parser.PromQLNode) (selectors []promParser.VectorSelector) { -LOOP: - for _, vs := range parser.WalkDownExpr[*promParser.VectorSelector](n) { - for _, bin := range parser.WalkUpExpr[*promParser.BinaryExpr](vs.Parent) { - if binExp := bin.Expr.(*promParser.BinaryExpr); binExp.Op != promParser.LOR { - continue +func selectorWithoutOffset(vs *promParser.VectorSelector) *promParser.VectorSelector { + if vs.OriginalOffset == 0 { + return vs + } + + s := &promParser.VectorSelector{} + *s = *vs + s.Offset = 0 + s.OriginalOffset = 0 + return s +} + +func getNonFallbackSelectors(n parser.PromQLExpr) (selectors []*promParser.VectorSelector) { + var hasVectorFallback bool + sources := utils.LabelsSource(n.Value.Value, n.Query.Expr) + for _, ls := range sources { + if ls.AlwaysReturns && len(ls.ReturnedNumbers) > 0 { + hasVectorFallback = true + break + } + } + for _, ls := range sources { + if !hasVectorFallback { + if ls.Selector != nil { + selectors = append(selectors, selectorWithoutOffset(ls.Selector)) } - for _, vec := range parser.WalkDownExpr[*promParser.Call](bin) { - if vecCall := vec.Expr.(*promParser.Call); vecCall.Func.Name == "vector" { - // vector seletor is under (...) OR vector() - // ignore it - slog.Debug( - "Metric uses vector() fallback value, ignore", - slog.String("selector", (vs.Expr.String())), - ) - continue LOOP - } + } + for _, js := range ls.Joins { + if js.Selector != nil { + selectors = append(selectors, selectorWithoutOffset(js.Selector)) } } - // copy node without offset - nc := promParser.VectorSelector{ - Name: vs.Expr.(*promParser.VectorSelector).Name, - LabelMatchers: vs.Expr.(*promParser.VectorSelector).LabelMatchers, + for _, us := range ls.Unless { + if !us.IsConditional { + continue + } + if us.Selector != nil { + selectors = append(selectors, selectorWithoutOffset(us.Selector)) + } } - selectors = append(selectors, nc) } return selectors } -func stripLabels(selector promParser.VectorSelector) promParser.VectorSelector { +func stripLabels(selector *promParser.VectorSelector) promParser.VectorSelector { s := promParser.VectorSelector{ Name: selector.Name, LabelMatchers: []*labels.Matcher{}, @@ -805,7 +820,7 @@ func stripLabels(selector promParser.VectorSelector) promParser.VectorSelector { return s } -func isDisabled(rule parser.Rule, selector promParser.VectorSelector) bool { +func isDisabled(rule parser.Rule, selector *promParser.VectorSelector) bool { for _, disable := range comments.Only[comments.Disable](rule.Comments, comments.DisableType) { if strings.HasPrefix(disable.Match, SeriesCheckName+"(") && strings.HasSuffix(disable.Match, ")") { cs := strings.TrimSuffix(strings.TrimPrefix(disable.Match, SeriesCheckName+"("), ")") @@ -823,7 +838,7 @@ func isDisabled(rule parser.Rule, selector promParser.VectorSelector) bool { return false } -func matchSelectorToMetric(selector promParser.VectorSelector, metric string) (bool, bool) { +func matchSelectorToMetric(selector *promParser.VectorSelector, metric string) (bool, bool) { // Try full string or name match first. if metric == selector.String() || metric == selector.Name { return true, true @@ -889,7 +904,7 @@ func orphanedDisableComments(ctx context.Context, rule parser.Rule, selectors [] continue } for _, selector := range selectors { - isMatch, ok := matchSelectorToMetric(selector, match) + isMatch, ok := matchSelectorToMetric(&selector, match) if !ok { continue } @@ -912,7 +927,7 @@ func orphanedRuleSetComments(rule parser.Rule, selectors []promParser.VectorSele matcher, key, value := parseRuleSet(ruleSet.Value) for _, selector := range selectors { if matcher != "" { - isMatch, _ := matchSelectorToMetric(selector, matcher) + isMatch, _ := matchSelectorToMetric(&selector, matcher) if !isMatch { continue } diff --git a/internal/checks/promql_series_test.go b/internal/checks/promql_series_test.go index 878a0a8a..53d8b4b0 100644 --- a/internal/checks/promql_series_test.go +++ b/internal/checks/promql_series_test.go @@ -4234,6 +4234,45 @@ func TestSeriesCheck(t *testing.T) { }, }, }, + { + description: "foo unless bar", + content: "- record: foo\n expr: foo unless bar\n", + checker: newSeriesCheck, + prometheus: newSimpleProm, + problems: noProblems, + mocks: []*prometheusMock{ + { + conds: []requestCondition{ + requireQueryPath, + formCond{key: "query", value: "count(foo)"}, + }, + resp: respondWithSingleInstantVector(), + }, + }, + }, + { + description: "foo unless bar > 5", + content: "- record: foo\n expr: foo unless bar > 5\n", + checker: newSeriesCheck, + prometheus: newSimpleProm, + problems: noProblems, + mocks: []*prometheusMock{ + { + conds: []requestCondition{ + requireQueryPath, + formCond{key: "query", value: "count(foo)"}, + }, + resp: respondWithSingleInstantVector(), + }, + { + conds: []requestCondition{ + requireQueryPath, + formCond{key: "query", value: "count(bar)"}, + }, + resp: respondWithSingleInstantVector(), + }, + }, + }, } runTests(t, testCases) } diff --git a/internal/parser/utils/source.go b/internal/parser/utils/source.go index 0c0c0a68..85c867dc 100644 --- a/internal/parser/utils/source.go +++ b/internal/parser/utils/source.go @@ -28,7 +28,9 @@ type ExcludedLabel struct { } type Source struct { - Selectors []*promParser.VectorSelector + Joins []Source // Any other sources this source joins with. + Unless []Source // Any other sources this source is suppressed by. + Selector *promParser.VectorSelector Call *promParser.Call ExcludeReason map[string]ExcludedLabel // Reason why a label was excluded Operation string @@ -41,6 +43,7 @@ type Source struct { FixedLabels bool // Labels are fixed and only allowed labels can be present. IsDead bool // True if this source cannot be reached and is dead code. AlwaysReturns bool // True if this source always returns results. + IsConditional bool // True if this source is guarded by 'foo > 5' or other condition. } func LabelsSource(expr string, node promParser.Node) (src []Source) { @@ -57,8 +60,7 @@ func walkNode(expr string, node promParser.Node) (src []Source) { src = append(src, parseBinOps(expr, n)...) case *promParser.Call: - s = parseCall(expr, n) - src = append(src, s) + src = append(src, parseCall(expr, n)...) case *promParser.MatrixSelector: src = append(src, walkNode(expr, n.VectorSelector)...) @@ -113,8 +115,8 @@ func walkNode(expr string, node promParser.Node) (src []Source) { case *promParser.VectorSelector: s.Type = SelectorSource s.Returns = promParser.ValueTypeVector - s.Selectors = append(s.Selectors, n) - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, n)...) + s.Selector = n + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, n)...) src = append(src, s) default: @@ -145,6 +147,31 @@ func appendToSlice(dst []string, values ...string) []string { return dst } +func includeLabel(s Source, names ...string) Source { + s.ExcludedLabels = removeFromSlice(s.ExcludedLabels, names...) + for _, name := range names { + delete(s.ExcludeReason, name) + } + s.IncludedLabels = appendToSlice(s.IncludedLabels, names...) + return s +} + +func guaranteeLabel(s Source, names ...string) Source { + s.ExcludedLabels = removeFromSlice(s.ExcludedLabels, names...) + for _, name := range names { + delete(s.ExcludeReason, name) + } + s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, names...) + return s +} + +func excludeLabel(s Source, names ...string) Source { + s.ExcludedLabels = appendToSlice(s.ExcludedLabels, names...) + s.IncludedLabels = removeFromSlice(s.IncludedLabels, names...) + s.GuaranteedLabels = removeFromSlice(s.GuaranteedLabels, names...) + return s +} + func setInMap(dst map[string]ExcludedLabel, key string, val ExcludedLabel) map[string]ExcludedLabel { if dst == nil { dst = map[string]ExcludedLabel{} @@ -155,32 +182,25 @@ func setInMap(dst map[string]ExcludedLabel, key string, val ExcludedLabel) map[s var guaranteedLabelsMatches = []labels.MatchType{labels.MatchEqual, labels.MatchRegexp} -func labelsFromSelectors(matches []labels.MatchType, selectors ...*promParser.VectorSelector) (names []string) { +func labelsFromSelectors(matches []labels.MatchType, selector *promParser.VectorSelector) (names []string) { nameCount := map[string]int{} var ok bool - for _, selector := range selectors { - // Any label used in positive filters is gurnateed to be present. - for _, lm := range selector.LabelMatchers { - if lm.Name == labels.MetricName { - continue - } + // Any label used in positive filters is gurnateed to be present. + for _, lm := range selector.LabelMatchers { + if lm.Name == labels.MetricName { + continue + } - if !slices.Contains(matches, lm.Type) { - continue - } + if !slices.Contains(matches, lm.Type) { + continue + } - names = appendToSlice(names, lm.Name) + names = appendToSlice(names, lm.Name) - if _, ok = nameCount[lm.Name]; !ok { - nameCount[lm.Name] = 0 - } - nameCount[lm.Name]++ - } - } - for name, cnt := range nameCount { - if cnt != len(selectors) { - names = removeFromSlice(names, name) + if _, ok = nameCount[lm.Name]; !ok { + nameCount[lm.Name] = 0 } + nameCount[lm.Name]++ } return names } @@ -236,10 +256,8 @@ func walkAggregation(expr string, n *promParser.AggregateExpr) (src []Source) { for _, s = range parseAggregation(expr, n) { s.Operation = "count_values" // Param is the label to store the count value in. - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, n.Param.(*promParser.StringLiteral).Val) - s.IncludedLabels = appendToSlice(s.IncludedLabels, n.Param.(*promParser.StringLiteral).Val) - s.ExcludedLabels = removeFromSlice(s.ExcludedLabels, n.Param.(*promParser.StringLiteral).Val) - delete(s.ExcludeReason, n.Param.(*promParser.StringLiteral).Val) + s = includeLabel(s, n.Param.(*promParser.StringLiteral).Val) + s = guaranteeLabel(s, n.Param.(*promParser.StringLiteral).Val) src = append(src, s) } case promParser.QUANTILE: @@ -278,9 +296,7 @@ func parseAggregation(expr string, n *promParser.AggregateExpr) (src []Source) { var s Source for _, s = range walkNode(expr, n.Expr) { if n.Without { - s.ExcludedLabels = appendToSlice(s.ExcludedLabels, n.Grouping...) - s.IncludedLabels = removeFromSlice(s.IncludedLabels, n.Grouping...) - s.GuaranteedLabels = removeFromSlice(s.GuaranteedLabels, n.Grouping...) + s = excludeLabel(s, n.Grouping...) for _, name := range n.Grouping { s.ExcludeReason = setInMap( s.ExcludeReason, @@ -307,10 +323,7 @@ func parseAggregation(expr string, n *promParser.AggregateExpr) (src []Source) { } else { // Check if source of labels already fixes them. if !s.FixedLabels { - s.IncludedLabels = appendToSlice(s.IncludedLabels, n.Grouping...) - for _, name := range n.Grouping { - s.ExcludedLabels = removeFromSlice(s.ExcludedLabels, name) - } + s = includeLabel(s, n.Grouping...) s.ExcludeReason = setInMap( s.ExcludeReason, "", @@ -337,55 +350,36 @@ func parseAggregation(expr string, n *promParser.AggregateExpr) (src []Source) { return src } -func parseCall(expr string, n *promParser.Call) (s Source) { - s.Type = FuncSource - s.Operation = n.Func.Name - s.Call = n - - var vt promParser.ValueType - for i, e := range n.Args { - if i >= len(n.Func.ArgTypes) { - vt = n.Func.ArgTypes[len(n.Func.ArgTypes)-1] - } else { - vt = n.Func.ArgTypes[i] - } - - // nolint: exhaustive - switch vt { - case promParser.ValueTypeVector, promParser.ValueTypeMatrix: - for _, es := range walkNode(expr, e) { - s.Selectors = append(s.Selectors, es.Selectors...) - } - } - } - +func parsePromQLFunc(s Source, expr string, n *promParser.Call) Source { switch n.Func.Name { case "abs", "sgn", "acos", "acosh", "asin", "asinh", "atan", "atanh", "cos", "cosh", "sin", "sinh", "tan", "tanh": // No change to labels. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) case "ceil", "floor", "round": // No change to labels. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) case "changes", "resets": // No change to labels. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) case "clamp", "clamp_max", "clamp_min": // No change to labels. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) case "absent", "absent_over_time": s.Returns = promParser.ValueTypeVector s.FixedLabels = true - for _, name := range labelsFromSelectors([]labels.MatchType{labels.MatchEqual}, s.Selectors...) { - s.IncludedLabels = appendToSlice(s.IncludedLabels, name) - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, name) + s.IncludedLabels = nil + s.GuaranteedLabels = nil + for _, name := range labelsFromSelectors([]labels.MatchType{labels.MatchEqual}, s.Selector) { + s = includeLabel(s, name) + s = guaranteeLabel(s, name) } s.ExcludeReason = setInMap( s.ExcludeReason, @@ -404,7 +398,7 @@ If you're hoping to get instance specific labels this way and alert when some ta case "avg_over_time", "count_over_time", "last_over_time", "max_over_time", "min_over_time", "present_over_time", "quantile_over_time", "stddev_over_time", "stdvar_over_time", "sum_over_time": // No change to labels. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) case "days_in_month", "day_of_month", "day_of_week", "day_of_year", "hour", "minute", "month", "year": s.Returns = promParser.ValueTypeVector @@ -425,34 +419,34 @@ If you're hoping to get instance specific labels this way and alert when some ta }, ) } else { - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) } case "deg", "rad", "ln", "log10", "log2", "sqrt", "exp": // No change to labels. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) case "delta", "idelta", "increase", "deriv", "irate", "rate": // No change to labels. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) case "histogram_avg", "histogram_count", "histogram_sum", "histogram_stddev", "histogram_stdvar", "histogram_fraction", "histogram_quantile": // No change to labels. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) case "holt_winters", "predict_linear": // No change to labels. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) case "label_replace", "label_join": // One label added to the results. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, s.Call.Args[1].(*promParser.StringLiteral).Val) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) + s = guaranteeLabel(s, s.Call.Args[1].(*promParser.StringLiteral).Val) case "pi": s.Returns = promParser.ValueTypeScalar @@ -506,7 +500,7 @@ If you're hoping to get instance specific labels this way and alert when some ta case "timestamp": // No change to labels. s.Returns = promParser.ValueTypeVector - s.GuaranteedLabels = appendToSlice(s.GuaranteedLabels, labelsFromSelectors(guaranteedLabelsMatches, s.Selectors...)...) + s = guaranteeLabel(s, labelsFromSelectors(guaranteedLabelsMatches, s.Selector)...) case "vector": s.Returns = promParser.ValueTypeVector @@ -534,6 +528,38 @@ If you're hoping to get instance specific labels this way and alert when some ta return s } +func parseCall(expr string, n *promParser.Call) (src []Source) { + var vt promParser.ValueType + for i, e := range n.Args { + if i >= len(n.Func.ArgTypes) { + vt = n.Func.ArgTypes[len(n.Func.ArgTypes)-1] + } else { + vt = n.Func.ArgTypes[i] + } + + switch vt { + case promParser.ValueTypeVector, promParser.ValueTypeMatrix: + for _, es := range walkNode(expr, e) { + es.Type = FuncSource + es.Operation = n.Func.Name + es.Call = n + src = append(src, parsePromQLFunc(es, expr, n)) + } + case promParser.ValueTypeNone, promParser.ValueTypeScalar, promParser.ValueTypeString: + } + } + + if len(src) == 0 { + var s Source + s.Type = FuncSource + s.Operation = n.Func.Name + s.Call = n + src = append(src, parsePromQLFunc(s, expr, n)) + } + + return src +} + func parseBinOps(expr string, n *promParser.BinaryExpr) (src []Source) { var s Source switch { @@ -546,7 +572,9 @@ func parseBinOps(expr string, n *promParser.BinaryExpr) (src []Source) { lhs := walkNode(expr, n.LHS) rhs := walkNode(expr, n.RHS) for _, ls := range lhs { + ls.IsConditional = n.Op.IsComparisonOperator() for _, rs := range rhs { + rs.IsConditional = n.Op.IsComparisonOperator() switch { case ls.AlwaysReturns && rs.AlwaysReturns: // Both sides always return something @@ -569,15 +597,13 @@ func parseBinOps(expr string, n *promParser.BinaryExpr) (src []Source) { // foo{} + bar{} // foo{} + on(...) bar{} // foo{} + ignoring(...) bar{} + // foo{} / bar{} case n.VectorMatching.Card == promParser.CardOneToOne: + rhs := walkNode(expr, n.RHS) for _, s = range walkNode(expr, n.LHS) { if n.VectorMatching.On { s.FixedLabels = true - s.IncludedLabels = appendToSlice(s.IncludedLabels, n.VectorMatching.MatchingLabels...) - s.ExcludedLabels = removeFromSlice(s.ExcludedLabels, n.VectorMatching.MatchingLabels...) - for _, name := range n.VectorMatching.MatchingLabels { - delete(s.ExcludeReason, name) - } + s = includeLabel(s, n.VectorMatching.MatchingLabels...) s.ExcludeReason = setInMap( s.ExcludeReason, "", @@ -596,9 +622,7 @@ func parseBinOps(expr string, n *promParser.BinaryExpr) (src []Source) { }, ) } else { - s.IncludedLabels = removeFromSlice(s.IncludedLabels, n.VectorMatching.MatchingLabels...) - s.GuaranteedLabels = removeFromSlice(s.GuaranteedLabels, n.VectorMatching.MatchingLabels...) - s.ExcludedLabels = appendToSlice(s.ExcludedLabels, n.VectorMatching.MatchingLabels...) + s = excludeLabel(s, n.VectorMatching.MatchingLabels...) for _, name := range n.VectorMatching.MatchingLabels { s.ExcludeReason = setInMap( s.ExcludeReason, @@ -622,61 +646,54 @@ func parseBinOps(expr string, n *promParser.BinaryExpr) (src []Source) { if s.Operation == "" { s.Operation = n.VectorMatching.Card.String() } + s.Joins = append(s.Joins, rhs...) + s.IsConditional = n.Op.IsComparisonOperator() src = append(src, s) } // foo{} + on(...) group_left(...) bar{} // foo{} + ignoring(...) group_left(...) bar{} case n.VectorMatching.Card == promParser.CardOneToMany: + lhs := walkNode(expr, n.LHS) for _, s = range walkNode(expr, n.RHS) { - s.IncludedLabels = appendToSlice(s.IncludedLabels, n.VectorMatching.Include...) + s = includeLabel(s, n.VectorMatching.Include...) if n.VectorMatching.On { - s.IncludedLabels = appendToSlice(s.IncludedLabels, n.VectorMatching.MatchingLabels...) - for _, name := range n.VectorMatching.MatchingLabels { - delete(s.ExcludeReason, name) - } - } - s.ExcludedLabels = removeFromSlice(s.ExcludedLabels, n.VectorMatching.Include...) - for _, name := range n.VectorMatching.Include { - delete(s.ExcludeReason, name) + s = includeLabel(s, n.VectorMatching.MatchingLabels...) } if s.Operation == "" { s.Operation = n.VectorMatching.Card.String() } + s.Joins = append(s.Joins, lhs...) + s.IsConditional = n.Op.IsComparisonOperator() src = append(src, s) } // foo{} + on(...) group_right(...) bar{} // foo{} + ignoring(...) group_right(...) bar{} case n.VectorMatching.Card == promParser.CardManyToOne: + rhs := walkNode(expr, n.RHS) for _, s = range walkNode(expr, n.LHS) { - s.IncludedLabels = appendToSlice(s.IncludedLabels, n.VectorMatching.Include...) + s = includeLabel(s, n.VectorMatching.Include...) if n.VectorMatching.On { - s.IncludedLabels = appendToSlice(s.IncludedLabels, n.VectorMatching.MatchingLabels...) - for _, name := range n.VectorMatching.MatchingLabels { - delete(s.ExcludeReason, name) - } - } - s.ExcludedLabels = removeFromSlice(s.ExcludedLabels, n.VectorMatching.Include...) - for _, name := range n.VectorMatching.Include { - delete(s.ExcludeReason, name) + s = includeLabel(s, n.VectorMatching.MatchingLabels...) } if s.Operation == "" { s.Operation = n.VectorMatching.Card.String() } + s.Joins = append(s.Joins, rhs...) + s.IsConditional = n.Op.IsComparisonOperator() src = append(src, s) } // foo{} and on(...) bar{} // foo{} and ignoring(...) bar{} + // foo{} unless bar{} case n.VectorMatching.Card == promParser.CardManyToMany: var lhsCanBeEmpty bool // true if any of the LHS query can produce empty results. + rhs := walkNode(expr, n.RHS) for _, s = range walkNode(expr, n.LHS) { if n.VectorMatching.On { - s.IncludedLabels = appendToSlice(s.IncludedLabels, n.VectorMatching.MatchingLabels...) - for _, name := range n.VectorMatching.MatchingLabels { - delete(s.ExcludeReason, name) - } + s = includeLabel(s, n.VectorMatching.MatchingLabels...) } if s.Operation == "" { s.Operation = n.VectorMatching.Card.String() @@ -684,10 +701,16 @@ func parseBinOps(expr string, n *promParser.BinaryExpr) (src []Source) { if !s.AlwaysReturns { lhsCanBeEmpty = true } + switch { + case n.Op == promParser.LUNLESS: + s.Unless = append(s.Unless, rhs...) + case n.Op != promParser.LOR: + s.Joins = append(s.Joins, rhs...) + } src = append(src, s) } if n.Op == promParser.LOR { - for _, s = range walkNode(expr, n.RHS) { + for _, s = range rhs { if s.Operation == "" { s.Operation = n.VectorMatching.Card.String() } diff --git a/internal/parser/utils/source_test.go b/internal/parser/utils/source_test.go index 5564128a..744a2d95 100644 --- a/internal/parser/utils/source_test.go +++ b/internal/parser/utils/source_test.go @@ -3,7 +3,6 @@ package utils_test import ( "strings" "testing" - "time" "github.com/stretchr/testify/require" @@ -11,33 +10,22 @@ import ( "github.com/cloudflare/pint/internal/parser/utils" promParser "github.com/prometheus/prometheus/promql/parser" - "github.com/prometheus/prometheus/promql/parser/posrange" ) +func mustParse[T any](t *testing.T, s string, offset int) T { + m, err := promParser.ParseExpr(strings.Repeat(" ", offset) + s) + require.NoErrorf(t, err, "failed to parse vector selector: %s", s) + n, ok := m.(T) + require.True(t, ok, "failed to convert %q to %t\n", s, n) + return n +} + func TestLabelsSource(t *testing.T) { type testCaseT struct { expr string output []utils.Source } - mustParseVector := func(s string, offset int) *promParser.VectorSelector { - m, err := promParser.ParseExpr(s) - require.NoErrorf(t, err, "failed to parse vector selector: %s", s) - v := m.(*promParser.VectorSelector) - v.PosRange.Start += posrange.Pos(offset) - v.PosRange.End += posrange.Pos(offset) - return v - } - - mustParseMatrix := func(s string, offset int) *promParser.MatrixSelector { - e, err := promParser.ParseExpr(s) - require.NoErrorf(t, err, "failed to parse matrix selector: %s", s) - m := e.(*promParser.MatrixSelector) - m.VectorSelector = mustParseVector(m.VectorSelector.String(), offset) - m.EndPos += posrange.Pos(offset) - return m - } - testCases := []testCaseT{ { expr: "1", @@ -91,6 +79,7 @@ func TestLabelsSource(t *testing.T) { Fragment: "2", }, }, + IsConditional: true, }, }, }, @@ -110,6 +99,7 @@ func TestLabelsSource(t *testing.T) { Fragment: "2", }, }, + IsConditional: true, }, }, }, @@ -129,6 +119,7 @@ func TestLabelsSource(t *testing.T) { Fragment: "2", }, }, + IsConditional: true, }, }, }, @@ -147,6 +138,7 @@ func TestLabelsSource(t *testing.T) { Fragment: "2", }, }, + IsConditional: true, }, }, }, @@ -166,6 +158,7 @@ func TestLabelsSource(t *testing.T) { Fragment: "2", }, }, + IsConditional: true, }, }, }, @@ -185,6 +178,7 @@ func TestLabelsSource(t *testing.T) { Fragment: "20", }, }, + IsConditional: true, }, }, }, @@ -213,17 +207,13 @@ func TestLabelsSource(t *testing.T) { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector("foo", 1), - }, + Selector: mustParse[*promParser.VectorSelector](t, "foo", 1), }, { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector("bar", 8), - }, + Selector: mustParse[*promParser.VectorSelector](t, "bar", 8), }, }, }, @@ -234,9 +224,7 @@ func TestLabelsSource(t *testing.T) { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector("foo", 1), - }, + Selector: mustParse[*promParser.VectorSelector](t, "foo", 1), }, { Type: utils.FuncSource, @@ -251,29 +239,7 @@ func TestLabelsSource(t *testing.T) { Fragment: "vector(2)", }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "vector", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeScalar, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.NumberLiteral{ - Val: 2, - PosRange: posrange.PositionRange{ - Start: 15, - End: 16, - }, - }, - }, - PosRange: posrange.PositionRange{ - Start: 8, - End: 17, - }, - }, + Call: mustParse[*promParser.Call](t, "vector(2)", 8), }, }, }, @@ -284,8 +250,30 @@ func TestLabelsSource(t *testing.T) { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector("foo", 1), + Selector: mustParse[*promParser.VectorSelector](t, "foo", 1), + Joins: []utils.Source{ + { + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "vector", + FixedLabels: true, + AlwaysReturns: true, + ReturnedNumbers: []float64{2}, + Call: mustParse[*promParser.Call](t, "vector(2)", 22), + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Calling `vector()` will return a vector value with no labels.", + Fragment: "vector(2)", + }, + }, + }, + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardManyToMany.String(), + Selector: mustParse[*promParser.VectorSelector](t, "bar", 35), + IsDead: true, + }, }, }, { @@ -301,27 +289,29 @@ func TestLabelsSource(t *testing.T) { Fragment: "vector(5)", }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "vector", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeScalar, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.NumberLiteral{ - Val: 5, - PosRange: posrange.PositionRange{ - Start: 15, - End: 16, + Call: mustParse[*promParser.Call](t, "vector(5)", 8), + Joins: []utils.Source{ + { + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "vector", + FixedLabels: true, + AlwaysReturns: true, + ReturnedNumbers: []float64{2}, + Call: mustParse[*promParser.Call](t, "vector(2)", 22), + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Calling `vector()` will return a vector value with no labels.", + Fragment: "vector(2)", }, }, }, - PosRange: posrange.PositionRange{ - Start: 8, - End: 17, + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardManyToMany.String(), + Selector: mustParse[*promParser.VectorSelector](t, "bar", 35), + IsDead: true, }, }, }, @@ -342,6 +332,7 @@ func TestLabelsSource(t *testing.T) { Fragment: "1", }, }, + IsConditional: true, }, }, }, @@ -360,6 +351,7 @@ func TestLabelsSource(t *testing.T) { Fragment: "20", }, }, + IsConditional: true, }, }, }, @@ -384,11 +376,19 @@ func TestLabelsSource(t *testing.T) { expr: "foo", output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector("foo", 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "foo", 0), + }, + }, + }, + { + expr: "foo offset 5m", + output: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "foo offset 5m", 0), }, }, }, @@ -396,11 +396,9 @@ func TestLabelsSource(t *testing.T) { expr: `foo{job="bar"}`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="bar"}`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="bar"}`, 0), GuaranteedLabels: []string{"job"}, }, }, @@ -409,20 +407,16 @@ func TestLabelsSource(t *testing.T) { expr: `foo{job="bar"} or bar{job="foo"}`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="bar"}`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="bar"}`, 0), Operation: promParser.CardManyToMany.String(), GuaranteedLabels: []string{"job"}, }, { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector(`bar{job="foo"}`, 18), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar{job="foo"}`, 18), Operation: promParser.CardManyToMany.String(), GuaranteedLabels: []string{"job"}, }, @@ -432,20 +426,16 @@ func TestLabelsSource(t *testing.T) { expr: `foo{a="bar"} or bar{b="foo"}`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{a="bar"}`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `foo{a="bar"}`, 0), Operation: promParser.CardManyToMany.String(), GuaranteedLabels: []string{"a"}, }, { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector(`bar{b="foo"}`, 16), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar{b="foo"}`, 16), Operation: promParser.CardManyToMany.String(), GuaranteedLabels: []string{"b"}, }, @@ -455,11 +445,9 @@ func TestLabelsSource(t *testing.T) { expr: "foo[5m]", output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector("foo", 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "foo", 0), }, }, }, @@ -467,11 +455,9 @@ func TestLabelsSource(t *testing.T) { expr: "prometheus_build_info[2m:1m]", output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector("prometheus_build_info", 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "prometheus_build_info", 0), }, }, }, @@ -482,47 +468,8 @@ func TestLabelsSource(t *testing.T) { Type: utils.FuncSource, Returns: promParser.ValueTypeVector, Operation: "deriv", - Selectors: []*promParser.VectorSelector{ - mustParseVector("distance_covered_meters_total", 11), - }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "deriv", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeMatrix, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.SubqueryExpr{ - Expr: &promParser.Call{ - Func: &promParser.Function{ - Name: "rate", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeMatrix, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseMatrix(`distance_covered_meters_total[1m]`, 11), - }, - PosRange: posrange.PositionRange{ - Start: 6, - End: 45, - }, - }, - Range: time.Minute * 5, - Step: time.Minute, - EndPos: posrange.Pos(52), - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 53, - }, - }, + Selector: mustParse[*promParser.VectorSelector](t, "distance_covered_meters_total", 11), + Call: mustParse[*promParser.Call](t, "deriv(rate(distance_covered_meters_total[1m])[5m:1m])", 0), }, }, }, @@ -530,11 +477,9 @@ func TestLabelsSource(t *testing.T) { expr: "foo - 1", output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector("foo", 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "foo", 0), }, }, }, @@ -542,11 +487,9 @@ func TestLabelsSource(t *testing.T) { expr: "foo / 5", output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector("foo", 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "foo", 0), }, }, }, @@ -554,11 +497,9 @@ func TestLabelsSource(t *testing.T) { expr: "-foo", output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector("foo", 1), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "foo", 1), }, }, }, @@ -566,12 +507,28 @@ func TestLabelsSource(t *testing.T) { expr: `sum(foo{job="myjob"})`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 4), + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 4), + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation that removes all labels.", + Fragment: `sum(foo{job="myjob"})`, + }, }, + }, + }, + }, + { + expr: `sum(foo{job="myjob"}) > 20`, + output: []utils.Source{ + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 4), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -579,6 +536,7 @@ func TestLabelsSource(t *testing.T) { Fragment: `sum(foo{job="myjob"})`, }, }, + IsConditional: true, }, }, }, @@ -586,12 +544,10 @@ func TestLabelsSource(t *testing.T) { expr: `sum(foo{job="myjob"}) without(job)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 4), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 4), ExcludedLabels: []string{"job"}, ExcludeReason: map[string]utils.ExcludedLabel{ "job": { @@ -606,12 +562,10 @@ func TestLabelsSource(t *testing.T) { expr: `sum(foo) by(job)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 4), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 4), IncludedLabels: []string{"job"}, FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -627,12 +581,10 @@ func TestLabelsSource(t *testing.T) { expr: `sum(foo{job="myjob"}) by(job)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 4), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 4), IncludedLabels: []string{"job"}, GuaranteedLabels: []string{"job"}, FixedLabels: true, @@ -645,41 +597,37 @@ func TestLabelsSource(t *testing.T) { }, }, }, + { + expr: `abs(foo{job="myjob"} offset 5m)`, + output: []utils.Source{ + { + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "abs", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"} offset 5m`, 4), + Call: mustParse[*promParser.Call](t, `abs(foo{job="myjob"} offset 5m)`, 0), + GuaranteedLabels: []string{"job"}, + }, + }, + }, { expr: `abs(foo{job="myjob"} or bar{cluster="dev"})`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "abs", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 4), - mustParseVector(`bar{cluster="dev"}`, 24), - }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "abs", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.BinaryExpr{ - Op: promParser.LOR, - LHS: mustParseVector(`foo{job="myjob"}`, 4), - RHS: mustParseVector(`bar{cluster="dev"}`, 24), - VectorMatching: &promParser.VectorMatching{ - Card: promParser.CardManyToMany, - }, - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 43, - }, - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "abs", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 4), + GuaranteedLabels: []string{"job"}, + Call: mustParse[*promParser.Call](t, `abs(foo{job="myjob"} or bar{cluster="dev"})`, 0), + }, + { + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "abs", + Selector: mustParse[*promParser.VectorSelector](t, `bar{cluster="dev"}`, 24), + Call: mustParse[*promParser.Call](t, `abs(foo{job="myjob"} or bar{cluster="dev"})`, 0), + GuaranteedLabels: []string{"cluster"}, }, }, }, @@ -687,12 +635,10 @@ func TestLabelsSource(t *testing.T) { expr: `sum(foo{job="myjob"} or bar{cluster="dev"}) without(instance)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 4), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 4), GuaranteedLabels: []string{"job"}, ExcludedLabels: []string{"instance"}, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -703,12 +649,10 @@ func TestLabelsSource(t *testing.T) { }, }, { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`bar{cluster="dev"}`, 24), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `bar{cluster="dev"}`, 24), GuaranteedLabels: []string{"cluster"}, ExcludedLabels: []string{"instance"}, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -724,12 +668,10 @@ func TestLabelsSource(t *testing.T) { expr: `sum(foo{job="myjob"}) without(instance)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 4), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 4), GuaranteedLabels: []string{"job"}, ExcludedLabels: []string{"instance"}, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -745,12 +687,10 @@ func TestLabelsSource(t *testing.T) { expr: `min(foo{job="myjob"}) / max(foo{job="myjob"})`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "min", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 4), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "min", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 4), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -758,6 +698,21 @@ func TestLabelsSource(t *testing.T) { Fragment: `min(foo{job="myjob"})`, }, }, + Joins: []utils.Source{ + { + Type: utils.AggregateSource, + Operation: "max", + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 28), + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation that removes all labels.", + Fragment: `max(foo{job="myjob"})`, + }, + }, + }, + }, }, }, }, @@ -765,12 +720,10 @@ func TestLabelsSource(t *testing.T) { expr: `max(foo{job="myjob"}) / min(foo{job="myjob"})`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "max", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 4), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "max", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 4), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -778,6 +731,21 @@ func TestLabelsSource(t *testing.T) { Fragment: `max(foo{job="myjob"})`, }, }, + Joins: []utils.Source{ + { + Type: utils.AggregateSource, + Operation: "min", + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 28), + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation that removes all labels.", + Fragment: `min(foo{job="myjob"})`, + }, + }, + }, + }, }, }, }, @@ -785,12 +753,10 @@ func TestLabelsSource(t *testing.T) { expr: `avg(foo{job="myjob"}) by(job)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "avg", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 4), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "avg", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 4), GuaranteedLabels: []string{"job"}, IncludedLabels: []string{"job"}, FixedLabels: true, @@ -807,12 +773,10 @@ func TestLabelsSource(t *testing.T) { expr: `group(foo) by(job)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "group", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 6), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "group", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 6), IncludedLabels: []string{"job"}, FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -828,12 +792,10 @@ func TestLabelsSource(t *testing.T) { expr: `stddev(rate(foo[5m]))`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "stddev", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 12), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "stddev", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 12), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -848,12 +810,10 @@ func TestLabelsSource(t *testing.T) { expr: `stdvar(rate(foo[5m]))`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "stdvar", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 12), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "stdvar", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 12), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -871,26 +831,8 @@ func TestLabelsSource(t *testing.T) { Type: utils.FuncSource, Returns: promParser.ValueTypeVector, Operation: "stddev_over_time", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 17), - }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "stddev_over_time", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeMatrix, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseMatrix(`foo[5m]`, 17), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 25, - }, - }, + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 17), + Call: mustParse[*promParser.Call](t, `stddev_over_time(foo[5m])`, 0), }, }, }, @@ -901,26 +843,8 @@ func TestLabelsSource(t *testing.T) { Type: utils.FuncSource, Returns: promParser.ValueTypeVector, Operation: "stdvar_over_time", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 17), - }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "stdvar_over_time", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeMatrix, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseMatrix(`foo[5m]`, 17), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 25, - }, - }, + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 17), + Call: mustParse[*promParser.Call](t, `stdvar_over_time(foo[5m])`, 0), }, }, }, @@ -928,12 +852,10 @@ func TestLabelsSource(t *testing.T) { expr: `quantile(0.9, rate(foo[5m]))`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "quantile", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 19), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "quantile", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 19), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -948,12 +870,10 @@ func TestLabelsSource(t *testing.T) { expr: `count_values("version", build_version)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "count_values", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`build_version`, 24), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count_values", + Selector: mustParse[*promParser.VectorSelector](t, `build_version`, 24), GuaranteedLabels: []string{"version"}, IncludedLabels: []string{"version"}, FixedLabels: true, @@ -970,12 +890,10 @@ func TestLabelsSource(t *testing.T) { expr: `count_values("version", build_version) without(job)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "count_values", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`build_version`, 24), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count_values", + Selector: mustParse[*promParser.VectorSelector](t, `build_version`, 24), IncludedLabels: []string{"version"}, GuaranteedLabels: []string{"version"}, ExcludedLabels: []string{"job"}, @@ -992,12 +910,10 @@ func TestLabelsSource(t *testing.T) { expr: `count_values("version", build_version{job="foo"}) without(job)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "count_values", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`build_version{job="foo"}`, 24), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count_values", + Selector: mustParse[*promParser.VectorSelector](t, `build_version{job="foo"}`, 24), IncludedLabels: []string{"version"}, GuaranteedLabels: []string{"version"}, ExcludedLabels: []string{"job"}, @@ -1014,12 +930,10 @@ func TestLabelsSource(t *testing.T) { expr: `count_values("version", build_version) by(job)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "count_values", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`build_version`, 24), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count_values", + Selector: mustParse[*promParser.VectorSelector](t, `build_version`, 24), GuaranteedLabels: []string{"version"}, IncludedLabels: []string{"job", "version"}, FixedLabels: true, @@ -1036,13 +950,12 @@ func TestLabelsSource(t *testing.T) { expr: `topk(10, foo{job="myjob"}) > 10`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "topk", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 9), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "topk", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 9), GuaranteedLabels: []string{"job"}, + IsConditional: true, }, }, }, @@ -1053,17 +966,13 @@ func TestLabelsSource(t *testing.T) { Type: utils.AggregateSource, Returns: promParser.ValueTypeVector, Operation: "topk", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 9), - }, + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 9), }, { Type: utils.AggregateSource, Operation: "topk", Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector(`bar`, 16), - }, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 16), }, }, }, @@ -1074,26 +983,8 @@ func TestLabelsSource(t *testing.T) { Type: utils.FuncSource, Returns: promParser.ValueTypeVector, Operation: "rate", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 5), - }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "rate", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeMatrix, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseMatrix(`foo[10m]`, 5), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 14, - }, - }, + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 5), + Call: mustParse[*promParser.Call](t, `rate(foo[10m])`, 0), }, }, }, @@ -1101,12 +992,10 @@ func TestLabelsSource(t *testing.T) { expr: `sum(rate(foo[10m])) without(instance)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 9), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 9), ExcludedLabels: []string{"instance"}, ExcludeReason: map[string]utils.ExcludedLabel{ "instance": { @@ -1121,13 +1010,18 @@ func TestLabelsSource(t *testing.T) { expr: `foo{job="foo"} / bar`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Operation: promParser.CardOneToOne.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="foo"}`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardOneToOne.String(), + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="foo"}`, 0), GuaranteedLabels: []string{"job"}, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 17), + }, + }, }, }, }, @@ -1135,12 +1029,10 @@ func TestLabelsSource(t *testing.T) { expr: `foo{job="foo"} * on(instance) bar`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Operation: promParser.CardOneToOne.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="foo"}`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardOneToOne.String(), + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="foo"}`, 0), GuaranteedLabels: []string{"job"}, IncludedLabels: []string{"instance"}, FixedLabels: true, @@ -1150,6 +1042,13 @@ func TestLabelsSource(t *testing.T) { Fragment: `foo{job="foo"} * on(instance) bar`, }, }, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 30), + }, + }, }, }, }, @@ -1157,14 +1056,19 @@ func TestLabelsSource(t *testing.T) { expr: `foo{job="foo"} * on(instance) group_left(bar) bar`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Operation: promParser.CardManyToOne.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="foo"}`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardManyToOne.String(), + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="foo"}`, 0), IncludedLabels: []string{"bar", "instance"}, GuaranteedLabels: []string{"job"}, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 46), + }, + }, }, }, }, @@ -1172,14 +1076,20 @@ func TestLabelsSource(t *testing.T) { expr: `foo{job="foo"} * on(instance) group_left(cluster) bar{cluster="bar", ignored="true"}`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Operation: promParser.CardManyToOne.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="foo"}`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardManyToOne.String(), + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="foo"}`, 0), IncludedLabels: []string{"cluster", "instance"}, GuaranteedLabels: []string{"job"}, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar{cluster="bar", ignored="true"}`, 50), + GuaranteedLabels: []string{"cluster", "ignored"}, + }, + }, }, }, }, @@ -1187,14 +1097,20 @@ func TestLabelsSource(t *testing.T) { expr: `foo{job="foo", ignored="true"} * on(instance) group_right(job) bar{cluster="bar"}`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Operation: promParser.CardOneToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`bar{cluster="bar"}`, 63), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardOneToMany.String(), + Selector: mustParse[*promParser.VectorSelector](t, `bar{cluster="bar"}`, 63), IncludedLabels: []string{"job", "instance"}, GuaranteedLabels: []string{"cluster"}, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="foo", ignored="true"}`, 0), + GuaranteedLabels: []string{"job", "ignored"}, + }, + }, }, }, }, @@ -1202,12 +1118,10 @@ func TestLabelsSource(t *testing.T) { expr: `count(foo / bar)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "count", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 6), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 6), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -1215,6 +1129,13 @@ func TestLabelsSource(t *testing.T) { Fragment: `count(foo / bar)`, }, }, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 12), + }, + }, }, }, }, @@ -1222,12 +1143,10 @@ func TestLabelsSource(t *testing.T) { expr: `count(up{job="a"} / on () up{job="b"})`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "count", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`up{job="a"}`, 6), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count", + Selector: mustParse[*promParser.VectorSelector](t, `up{job="a"}`, 6), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -1235,6 +1154,14 @@ func TestLabelsSource(t *testing.T) { Fragment: `count(up{job="a"} / on () up{job="b"})`, }, }, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `up{job="b"}`, 26), + GuaranteedLabels: []string{"job"}, + }, + }, }, }, }, @@ -1242,12 +1169,10 @@ func TestLabelsSource(t *testing.T) { expr: `count(up{job="a"} / on (env) up{job="b"})`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "count", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`up{job="a"}`, 6), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count", + Selector: mustParse[*promParser.VectorSelector](t, `up{job="a"}`, 6), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -1255,6 +1180,14 @@ func TestLabelsSource(t *testing.T) { Fragment: `count(up{job="a"} / on (env) up{job="b"})`, }, }, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `up{job="b"}`, 29), + GuaranteedLabels: []string{"job"}, + }, + }, }, }, }, @@ -1262,13 +1195,18 @@ func TestLabelsSource(t *testing.T) { expr: `foo{job="foo", instance="1"} and bar`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="foo", instance="1"}`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardManyToMany.String(), + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="foo", instance="1"}`, 0), GuaranteedLabels: []string{"job", "instance"}, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 33), + }, + }, }, }, }, @@ -1276,14 +1214,19 @@ func TestLabelsSource(t *testing.T) { expr: `foo{job="foo", instance="1"} and on(cluster) bar`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="foo", instance="1"}`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardManyToMany.String(), + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="foo", instance="1"}`, 0), IncludedLabels: []string{"cluster"}, GuaranteedLabels: []string{"job", "instance"}, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 45), + }, + }, }, }, }, @@ -1294,9 +1237,7 @@ func TestLabelsSource(t *testing.T) { Type: utils.AggregateSource, Returns: promParser.ValueTypeVector, Operation: "topk", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 9), - }, + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 9), }, }, }, @@ -1307,9 +1248,7 @@ func TestLabelsSource(t *testing.T) { Type: utils.AggregateSource, Returns: promParser.ValueTypeVector, Operation: "topk", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 9), - }, + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 9), }, }, }, @@ -1320,9 +1259,7 @@ func TestLabelsSource(t *testing.T) { Type: utils.AggregateSource, Returns: promParser.ValueTypeVector, Operation: "topk", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 9), - }, + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 9), }, }, }, @@ -1330,12 +1267,10 @@ func TestLabelsSource(t *testing.T) { expr: `bottomk(10, sum(rate(foo[5m])) without(job))`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "bottomk", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 21), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "bottomk", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 21), ExcludedLabels: []string{"job"}, ExcludeReason: map[string]utils.ExcludedLabel{ "job": { @@ -1353,17 +1288,13 @@ func TestLabelsSource(t *testing.T) { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 0), - }, + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 0), }, { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`bar`, 7), - }, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 7), }, }, }, @@ -1374,25 +1305,19 @@ func TestLabelsSource(t *testing.T) { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 0), - }, + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 0), }, { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`bar`, 7), - }, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 7), }, { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`baz`, 14), - }, + Selector: mustParse[*promParser.VectorSelector](t, `baz`, 14), }, }, }, @@ -1403,25 +1328,19 @@ func TestLabelsSource(t *testing.T) { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 1), - }, + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 1), }, { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`bar`, 8), - }, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 8), }, { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`baz`, 16), - }, + Selector: mustParse[*promParser.VectorSelector](t, `baz`, 16), }, }, }, @@ -1432,22 +1351,67 @@ func TestLabelsSource(t *testing.T) { Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, Operation: promParser.CardManyToMany.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 0), + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 0), + Unless: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 11), + }, }, }, }, }, { - expr: `count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`, + expr: `foo unless bar > 5`, output: []utils.Source{ { - Type: utils.AggregateSource, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardManyToMany.String(), + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 0), + Unless: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 11), + IsConditional: true, + }, + }, + }, + }, + }, + { + expr: `foo unless bar unless baz`, + output: []utils.Source{ + { + Type: utils.SelectorSource, Returns: promParser.ValueTypeVector, - Operation: "count", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`up{job="foo", cluster="dev"}`, 10), + Operation: promParser.CardManyToMany.String(), + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 0), + Unless: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 11), + }, + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `baz`, 22), + }, }, + }, + }, + }, + { + expr: `count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`, + output: []utils.Source{ + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count", + Selector: mustParse[*promParser.VectorSelector](t, `up{job="foo", cluster="dev"}`, 10), ExcludedLabels: []string{"job", "cluster"}, // FIXME empty FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -1464,6 +1428,7 @@ func TestLabelsSource(t *testing.T) { Fragment: `count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`, }, }, + IsConditional: true, }, }, }, @@ -1482,21 +1447,7 @@ func TestLabelsSource(t *testing.T) { Fragment: `year()`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "year", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 1, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{}, - PosRange: posrange.PositionRange{ - Start: 0, - End: 6, - }, - }, + Call: mustParse[*promParser.Call](t, `year()`, 0), }, }, }, @@ -1507,26 +1458,8 @@ func TestLabelsSource(t *testing.T) { Type: utils.FuncSource, Returns: promParser.ValueTypeVector, Operation: "year", - Selectors: []*promParser.VectorSelector{ - mustParseVector("foo", 5), - }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "year", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 1, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector("foo", 5), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 9, - }, - }, + Selector: mustParse[*promParser.VectorSelector](t, "foo", 5), + Call: mustParse[*promParser.Call](t, `year(foo)`, 0), }, }, }, @@ -1534,53 +1467,12 @@ func TestLabelsSource(t *testing.T) { expr: `label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "label_join", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`up{job="api-server",src1="a",src2="b",src3="c"}`, 11), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "label_join", + Selector: mustParse[*promParser.VectorSelector](t, `up{job="api-server",src1="a",src2="b",src3="c"}`, 11), GuaranteedLabels: []string{"job", "src1", "src2", "src3", "foo"}, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "label_join", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - promParser.ValueTypeString, - promParser.ValueTypeString, - promParser.ValueTypeString, - }, - Variadic: -1, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`up{job="api-server",src1="a",src2="b",src3="c"}`, 11), - &promParser.StringLiteral{ - Val: "foo", - PosRange: posrange.PositionRange{Start: 60, End: 65}, - }, - &promParser.StringLiteral{ - Val: ",", - PosRange: posrange.PositionRange{Start: 67, End: 70}, - }, - &promParser.StringLiteral{ - Val: "src1", - PosRange: posrange.PositionRange{Start: 72, End: 78}, - }, - &promParser.StringLiteral{ - Val: "src2", - PosRange: posrange.PositionRange{Start: 80, End: 86}, - }, - &promParser.StringLiteral{ - Val: "src3", - PosRange: posrange.PositionRange{Start: 88, End: 94}, - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 95, - }, - }, + Call: mustParse[*promParser.Call](t, `label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")`, 0), }, }, }, @@ -1595,14 +1487,35 @@ and on(job) sum(foo:count) by(job) > 20`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo:sum`, 8), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo:sum`, 8), IncludedLabels: []string{"notify", "job"}, ExcludeReason: map[string]utils.ExcludedLabel{}, + IsConditional: false, // FIXME should be true + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `job:notify`, 68), + }, + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo:count`, 97), + IncludedLabels: []string{"job"}, + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.", + Fragment: `sum(foo:count) by(job)`, + }, + }, + IsConditional: true, + }, + }, }, }, }, @@ -1610,12 +1523,10 @@ sum(foo:count) by(job) > 20`, expr: `container_file_descriptors / on (instance, app_name) container_ulimits_soft{ulimit="max_open_files"}`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Operation: promParser.CardOneToOne.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`container_file_descriptors`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardOneToOne.String(), + Selector: mustParse[*promParser.VectorSelector](t, `container_file_descriptors`, 0), IncludedLabels: []string{"instance", "app_name"}, FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -1624,6 +1535,14 @@ sum(foo:count) by(job) > 20`, Fragment: `container_file_descriptors / on (instance, app_name) container_ulimits_soft{ulimit="max_open_files"}`, }, }, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `container_ulimits_soft{ulimit="max_open_files"}`, 53), + GuaranteedLabels: []string{"ulimit"}, + }, + }, }, }, }, @@ -1631,13 +1550,19 @@ sum(foo:count) by(job) > 20`, expr: `container_file_descriptors / on (instance, app_name) group_left() container_ulimits_soft{ulimit="max_open_files"}`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Operation: promParser.CardManyToOne.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`container_file_descriptors`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardManyToOne.String(), + Selector: mustParse[*promParser.VectorSelector](t, `container_file_descriptors`, 0), IncludedLabels: []string{"instance", "app_name"}, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `container_ulimits_soft{ulimit="max_open_files"}`, 66), + GuaranteedLabels: []string{"ulimit"}, + }, + }, }, }, }, @@ -1645,12 +1570,10 @@ sum(foo:count) by(job) > 20`, expr: `absent(foo{job="bar"})`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "absent", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="bar"}`, 7), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "absent", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="bar"}`, 7), IncludedLabels: []string{"job"}, GuaranteedLabels: []string{"job"}, FixedLabels: true, @@ -1660,23 +1583,7 @@ sum(foo:count) by(job) > 20`, Fragment: `absent(foo{job="bar"})`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "absent", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`foo{job="bar"}`, 7), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 22, - }, - }, + Call: mustParse[*promParser.Call](t, `absent(foo{job="bar"})`, 0), }, }, }, @@ -1684,12 +1591,10 @@ sum(foo:count) by(job) > 20`, expr: `absent(foo{job="bar", cluster!="dev", instance=~".+", env="prod"})`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "absent", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="bar", cluster!="dev", instance=~".+", env="prod"}`, 7), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "absent", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="bar", cluster!="dev", instance=~".+", env="prod"}`, 7), IncludedLabels: []string{"job", "env"}, GuaranteedLabels: []string{"job", "env"}, FixedLabels: true, @@ -1699,23 +1604,7 @@ sum(foo:count) by(job) > 20`, Fragment: `absent(foo{job="bar", cluster!="dev", instance=~".+", env="prod"})`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "absent", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`foo{job="bar", cluster!="dev", instance=~".+", env="prod"}`, 7), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 66, - }, - }, + Call: mustParse[*promParser.Call](t, `absent(foo{job="bar", cluster!="dev", instance=~".+", env="prod"})`, 0), }, }, }, @@ -1723,12 +1612,10 @@ sum(foo:count) by(job) > 20`, expr: `absent(sum(foo) by(job, instance))`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "absent", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 11), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "absent", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 11), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -1736,31 +1623,7 @@ sum(foo:count) by(job) > 20`, Fragment: `absent(sum(foo) by(job, instance))`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "absent", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.AggregateExpr{ - Op: promParser.SUM, - Expr: mustParseVector("foo", 11), - Grouping: []string{"job", "instance"}, - PosRange: posrange.PositionRange{ - Start: 7, - End: 33, - }, - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 34, - }, - }, + Call: mustParse[*promParser.Call](t, `absent(sum(foo) by(job, instance))`, 0), }, }, }, @@ -1768,12 +1631,10 @@ sum(foo:count) by(job) > 20`, expr: `absent(foo{job="prometheus", xxx="1"}) AND on(job) prometheus_build_info`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "absent", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="prometheus", xxx="1"}`, 7), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "absent", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="prometheus", xxx="1"}`, 7), IncludedLabels: []string{"job", "xxx"}, GuaranteedLabels: []string{"job", "xxx"}, FixedLabels: true, @@ -1783,21 +1644,12 @@ sum(foo:count) by(job) > 20`, Fragment: `absent(foo{job="prometheus", xxx="1"})`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "absent", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`foo{job="prometheus", xxx="1"}`, 7), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 38, + Call: mustParse[*promParser.Call](t, `absent(foo{job="prometheus", xxx="1"})`, 0), + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "prometheus_build_info", 51), }, }, }, @@ -1807,12 +1659,10 @@ sum(foo:count) by(job) > 20`, expr: `1 + sum(foo) by(notjob)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 8), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 8), IncludedLabels: []string{"notjob"}, FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -1828,12 +1678,10 @@ sum(foo:count) by(job) > 20`, expr: `count(node_exporter_build_info) by (instance, version) != ignoring(package,version) group_left(foo) count(deb_package_version) by (instance, version, package)`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "count", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`node_exporter_build_info`, 6), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count", + Selector: mustParse[*promParser.VectorSelector](t, `node_exporter_build_info`, 6), IncludedLabels: []string{"instance", "version", "foo"}, // FIXME foo shouldn't be there because count() doesn't produce it FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -1842,6 +1690,23 @@ sum(foo:count) by(job) > 20`, Fragment: `count(node_exporter_build_info) by (instance, version)`, }, }, + IsConditional: true, + Joins: []utils.Source{ + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count", + Selector: mustParse[*promParser.VectorSelector](t, "deb_package_version", 106), + IncludedLabels: []string{"instance", "version", "package"}, + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation with `by(instance, version, package)`, only labels included inside `by(...)` will be present on the results.", + Fragment: `count(deb_package_version) by (instance, version, package)`, + }, + }, + }, + }, }, }, }, @@ -1849,12 +1714,10 @@ sum(foo:count) by(job) > 20`, expr: `absent(foo) or absent(bar)`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "absent", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 7), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "absent", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 7), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -1862,31 +1725,13 @@ sum(foo:count) by(job) > 20`, Fragment: `absent(foo)`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "absent", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`foo`, 7), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 11, - }, - }, + Call: mustParse[*promParser.Call](t, `absent(foo)`, 0), }, { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "absent", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`bar`, 22), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "absent", + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 22), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -1894,23 +1739,7 @@ sum(foo:count) by(job) > 20`, Fragment: `absent(bar)`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "absent", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`bar`, 22), - }, - PosRange: posrange.PositionRange{ - Start: 15, - End: 26, - }, - }, + Call: mustParse[*promParser.Call](t, `absent(bar)`, 15), }, }, }, @@ -1918,12 +1747,10 @@ sum(foo:count) by(job) > 20`, expr: `absent_over_time(foo[5m]) or absent(bar)`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "absent_over_time", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 17), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "absent_over_time", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 17), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -1931,31 +1758,13 @@ sum(foo:count) by(job) > 20`, Fragment: `absent_over_time(foo[5m])`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "absent_over_time", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeMatrix, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseMatrix(`foo[5m]`, 17), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 25, - }, - }, + Call: mustParse[*promParser.Call](t, `absent_over_time(foo[5m])`, 0), }, { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "absent", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`bar`, 36), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "absent", + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 36), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -1963,23 +1772,7 @@ sum(foo:count) by(job) > 20`, Fragment: `absent(bar)`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "absent", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`bar`, 36), - }, - PosRange: posrange.PositionRange{ - Start: 29, - End: 40, - }, - }, + Call: mustParse[*promParser.Call](t, `absent(bar)`, 29), }, }, }, @@ -1987,12 +1780,10 @@ sum(foo:count) by(job) > 20`, expr: `bar * on() group_right(cluster, env) absent(foo{job="xxx"})`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "absent", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="xxx"}`, 44), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "absent", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="xxx"}`, 44), IncludedLabels: []string{"job", "cluster", "env"}, GuaranteedLabels: []string{"job"}, FixedLabels: true, @@ -2002,21 +1793,12 @@ sum(foo:count) by(job) > 20`, Fragment: `absent(foo{job="xxx"})`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "absent", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`foo{job="xxx"}`, 44), - }, - PosRange: posrange.PositionRange{ - Start: 37, - End: 59, + Call: mustParse[*promParser.Call](t, `absent(foo{job="xxx"})`, 37), + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "bar", 0), }, }, }, @@ -2026,12 +1808,10 @@ sum(foo:count) by(job) > 20`, expr: `bar * on() group_right() absent(foo{job="xxx"})`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "absent", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="xxx"}`, 32), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "absent", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="xxx"}`, 32), IncludedLabels: []string{"job"}, GuaranteedLabels: []string{"job"}, FixedLabels: true, @@ -2041,21 +1821,12 @@ sum(foo:count) by(job) > 20`, Fragment: `absent(foo{job="xxx"})`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "absent", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`foo{job="xxx"}`, 32), - }, - PosRange: posrange.PositionRange{ - Start: 25, - End: 47, + Call: mustParse[*promParser.Call](t, `absent(foo{job="xxx"})`, 25), + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "bar", 0), }, }, }, @@ -2077,29 +1848,7 @@ sum(foo:count) by(job) > 20`, Fragment: `vector(1)`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "vector", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeScalar, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.NumberLiteral{ - Val: 1, - PosRange: posrange.PositionRange{ - Start: 7, - End: 8, - }, - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 9, - }, - }, + Call: mustParse[*promParser.Call](t, `vector(1)`, 0), }, }, }, @@ -2118,39 +1867,7 @@ sum(foo:count) by(job) > 20`, Fragment: `vector(scalar(foo))`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "vector", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeScalar, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.Call{ - Func: &promParser.Function{ - Name: "scalar", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeScalar, - }, - Args: promParser.Expressions{ - mustParseVector("foo", 14), - }, - PosRange: posrange.PositionRange{ - Start: 7, - End: 18, - }, - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 19, - }, - }, + Call: mustParse[*promParser.Call](t, `vector(scalar(foo))`, 0), }, }, }, @@ -2169,40 +1886,8 @@ sum(foo:count) by(job) > 20`, Fragment: `vector(0.0 >= bool 0.5)`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "vector", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeScalar, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.BinaryExpr{ - Op: promParser.GTE, - LHS: &promParser.NumberLiteral{ - Val: 0, - PosRange: posrange.PositionRange{ - Start: 7, - End: 10, - }, - }, - RHS: &promParser.NumberLiteral{ - Val: 0.5, - PosRange: posrange.PositionRange{ - Start: 20, - End: 23, - }, - }, - ReturnBool: true, - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 24, - }, - }, + Call: mustParse[*promParser.Call](t, `vector(0.0 >= bool 0.5)`, 0), + IsConditional: true, }, }, }, @@ -2210,30 +1895,12 @@ sum(foo:count) by(job) > 20`, expr: `sum_over_time(foo{job="myjob"}[5m])`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "sum_over_time", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="myjob"}`, 14), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "sum_over_time", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="myjob"}`, 14), GuaranteedLabels: []string{"job"}, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "sum_over_time", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeMatrix, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseMatrix(`foo{job="myjob"}[5m]`, 14), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 35, - }, - }, + Call: mustParse[*promParser.Call](t, `sum_over_time(foo{job="myjob"}[5m])`, 0), }, }, }, @@ -2252,21 +1919,7 @@ sum(foo:count) by(job) > 20`, Fragment: `days_in_month()`, }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "days_in_month", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 1, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{}, - PosRange: posrange.PositionRange{ - Start: 0, - End: 15, - }, - }, + Call: mustParse[*promParser.Call](t, `days_in_month()`, 0), }, }, }, @@ -2274,30 +1927,12 @@ sum(foo:count) by(job) > 20`, expr: `days_in_month(foo{job="foo"})`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "days_in_month", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo{job="foo"}`, 14), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "days_in_month", + Selector: mustParse[*promParser.VectorSelector](t, `foo{job="foo"}`, 14), GuaranteedLabels: []string{"job"}, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "days_in_month", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - }, - Variadic: 1, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`foo{job="foo"}`, 14), - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 29, - }, - }, + Call: mustParse[*promParser.Call](t, `days_in_month(foo{job="foo"})`, 0), }, }, }, @@ -2305,60 +1940,32 @@ sum(foo:count) by(job) > 20`, expr: `label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "label_replace", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`up{job="api-server",service="a:c"}`, 14), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "label_replace", + Selector: mustParse[*promParser.VectorSelector](t, `up{job="api-server",service="a:c"}`, 14), GuaranteedLabels: []string{"job", "service", "foo"}, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "label_replace", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - promParser.ValueTypeString, - promParser.ValueTypeString, - promParser.ValueTypeString, - promParser.ValueTypeString, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - mustParseVector(`up{job="api-server",service="a:c"}`, 14), - &promParser.StringLiteral{ - Val: "foo", - PosRange: posrange.PositionRange{ - Start: 50, - End: 55, - }, - }, - &promParser.StringLiteral{ - Val: "$1", - PosRange: posrange.PositionRange{ - Start: 57, - End: 61, - }, - }, - &promParser.StringLiteral{ - Val: "service", - PosRange: posrange.PositionRange{ - Start: 63, - End: 72, - }, - }, - &promParser.StringLiteral{ - Val: "(.*):.*", - PosRange: posrange.PositionRange{ - Start: 74, - End: 83, - }, - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 84, + Call: mustParse[*promParser.Call](t, `label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")`, 0), + }, + }, + }, + { + expr: `label_replace(sum by (pod) (pod_status) > 0, "cluster", "$1", "pod", "(.*)")`, + output: []utils.Source{ + { + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "label_replace", + Selector: mustParse[*promParser.VectorSelector](t, `pod_status`, 28), + FixedLabels: true, + IsConditional: true, + IncludedLabels: []string{"pod"}, + GuaranteedLabels: []string{"cluster"}, + Call: mustParse[*promParser.Call](t, `label_replace(sum by (pod) (pod_status) > 0, "cluster", "$1", "pod", "(.*)")`, 0), + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation with `by(pod)`, only labels included inside `by(...)` will be present on the results.", + Fragment: `sum by (pod) (pod_status)`, }, }, }, @@ -2368,11 +1975,10 @@ sum(foo:count) by(job) > 20`, expr: `(time() - my_metric) > 5*3600`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector("my_metric", 10), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "my_metric", 10), + IsConditional: true, }, }, }, @@ -2380,12 +1986,10 @@ sum(foo:count) by(job) > 20`, expr: `up{instance="a", job="prometheus"} * ignoring(job) up{instance="a", job="pint"}`, output: []utils.Source{ { - Type: utils.SelectorSource, - Returns: promParser.ValueTypeVector, - Operation: promParser.CardOneToOne.String(), - Selectors: []*promParser.VectorSelector{ - mustParseVector(`up{instance="a", job="prometheus"}`, 0), - }, + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Operation: promParser.CardOneToOne.String(), + Selector: mustParse[*promParser.VectorSelector](t, `up{instance="a", job="prometheus"}`, 0), GuaranteedLabels: []string{"instance"}, ExcludedLabels: []string{"job"}, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -2394,6 +1998,14 @@ sum(foo:count) by(job) > 20`, Fragment: `up{instance="a", job="prometheus"} * ignoring(job) up{instance="a", job="pint"}`, }, }, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `up{instance="a", job="pint"}`, 51), + GuaranteedLabels: []string{"instance", "job"}, + }, + }, }, }, }, @@ -2408,12 +2020,10 @@ or avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_us `, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "avg", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"}`, 41), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "avg", + Selector: mustParse[*promParser.VectorSelector](t, `router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"}`, 41), ExcludedLabels: []string{"router", "colo_id", "instance"}, ExcludeReason: map[string]utils.ExcludedLabel{ "router": { @@ -2429,14 +2039,13 @@ or avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_us Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})`, }, }, + IsConditional: true, }, { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"}`, 155), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"}`, 155), GuaranteedLabels: []string{"cidr_use_case"}, ExcludedLabels: []string{"router", "colo_id", "instance"}, FixedLabels: true, @@ -2458,14 +2067,28 @@ or avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_us Fragment: "sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~\".*tier1.*\"})\n< on() count(colo_router_tier:disabled_pops:max{tier=\"1\",router=~\"edge.*\"}) * 0.4", }, }, + IsConditional: true, + Joins: []utils.Source{ + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "count", + Selector: mustParse[*promParser.VectorSelector](t, `colo_router_tier:disabled_pops:max{tier="1",router=~"edge.*"}`, 227), + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation that removes all labels.", + Fragment: `count(colo_router_tier:disabled_pops:max{tier="1",router=~"edge.*"})`, + }, + }, + }, + }, }, { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "avg", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"}`, 343), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "avg", + Selector: mustParse[*promParser.VectorSelector](t, `router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"}`, 343), GuaranteedLabels: []string{"cidr_use_case"}, ExcludedLabels: []string{"router", "colo_id", "instance"}, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -2482,6 +2105,7 @@ or avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_us Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})`, }, }, + IsConditional: true, }, }, }, @@ -2489,71 +2113,13 @@ or avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_us expr: `label_replace(sum(foo) without(instance), "instance", "none", "", "")`, output: []utils.Source{ { - Type: utils.FuncSource, - Returns: promParser.ValueTypeVector, - Operation: "label_replace", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 18), - }, + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "label_replace", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 18), GuaranteedLabels: []string{"instance"}, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "label_replace", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeVector, - promParser.ValueTypeString, - promParser.ValueTypeString, - promParser.ValueTypeString, - promParser.ValueTypeString, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.AggregateExpr{ - Op: promParser.SUM, - Expr: mustParseVector("foo", 18), - Grouping: []string{"instance"}, - Without: true, - PosRange: posrange.PositionRange{ - Start: 14, - End: 40, - }, - }, - &promParser.StringLiteral{ - Val: "instance", - PosRange: posrange.PositionRange{ - Start: 42, - End: 52, - }, - }, - &promParser.StringLiteral{ - Val: "none", - PosRange: posrange.PositionRange{ - Start: 54, - End: 60, - }, - }, - &promParser.StringLiteral{ - Val: "", - PosRange: posrange.PositionRange{ - Start: 62, - End: 64, - }, - }, - &promParser.StringLiteral{ - Val: "", - PosRange: posrange.PositionRange{ - Start: 66, - End: 68, - }, - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 69, - }, - }, + ExcludeReason: map[string]utils.ExcludedLabel{}, + Call: mustParse[*promParser.Call](t, `label_replace(sum(foo) without(instance), "instance", "none", "", "")`, 0), }, }, }, @@ -2566,12 +2132,10 @@ sum by (region, target, colo_name) ( ) == 0`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`probe_success{job="abc"}`, 56), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `probe_success{job="abc"}`, 56), IncludedLabels: []string{"region", "target", "colo_name"}, FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ @@ -2580,6 +2144,7 @@ sum by (region, target, colo_name) ( Fragment: "sum by (region, target, colo_name) (\n sum_over_time(probe_success{job=\"abc\"}[5m])\n\tor\n\tvector(1)\n)", }, }, + IsConditional: true, }, { Type: utils.AggregateSource, @@ -2595,6 +2160,7 @@ sum by (region, target, colo_name) ( Fragment: "vector(1)", }, }, + IsConditional: true, }, }, }, @@ -2614,38 +2180,14 @@ sum by (region, target, colo_name) ( Fragment: "vector(1)", }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "vector", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeScalar, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.NumberLiteral{ - Val: 1, - PosRange: posrange.PositionRange{ - Start: 7, - End: 8, - }, - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 9, - }, - }, + Call: mustParse[*promParser.Call](t, "vector(1)", 0), }, { Type: utils.SelectorSource, Operation: promParser.CardManyToMany.String(), Returns: promParser.ValueTypeVector, - Selectors: []*promParser.VectorSelector{ - mustParseVector("foo", 13), - }, - IsDead: true, + Selector: mustParse[*promParser.VectorSelector](t, "foo", 13), + IsDead: true, }, }, }, @@ -2666,29 +2208,8 @@ sum by (region, target, colo_name) ( Fragment: "vector(0)", }, }, - Call: &promParser.Call{ - Func: &promParser.Function{ - Name: "vector", - ArgTypes: []promParser.ValueType{ - promParser.ValueTypeScalar, - }, - Variadic: 0, - ReturnType: promParser.ValueTypeVector, - }, - Args: promParser.Expressions{ - &promParser.NumberLiteral{ - Val: 0, - PosRange: posrange.PositionRange{ - Start: 7, - End: 8, - }, - }, - }, - PosRange: posrange.PositionRange{ - Start: 0, - End: 9, - }, - }, + Call: mustParse[*promParser.Call](t, "vector(0)", 0), + IsConditional: true, }, }, }, @@ -2696,12 +2217,10 @@ sum by (region, target, colo_name) ( expr: `sum(foo or vector(0)) > 0`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 4), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 4), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -2709,6 +2228,7 @@ sum by (region, target, colo_name) ( Fragment: `sum(foo or vector(0))`, }, }, + IsConditional: true, }, { Type: utils.AggregateSource, @@ -2724,6 +2244,7 @@ sum by (region, target, colo_name) ( Fragment: "sum(foo or vector(0))", }, }, + IsConditional: true, }, }, }, @@ -2731,12 +2252,10 @@ sum by (region, target, colo_name) ( expr: `(sum(foo or vector(1)) > 0) == 2`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 5), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 5), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -2744,6 +2263,7 @@ sum by (region, target, colo_name) ( Fragment: `sum(foo or vector(1))`, }, }, + IsConditional: true, }, { Type: utils.AggregateSource, @@ -2759,6 +2279,7 @@ sum by (region, target, colo_name) ( Fragment: "sum(foo or vector(1))", }, }, + IsConditional: true, }, }, }, @@ -2766,12 +2287,10 @@ sum by (region, target, colo_name) ( expr: `(sum(foo or vector(1)) > 0) != 2`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 5), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 5), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -2779,6 +2298,7 @@ sum by (region, target, colo_name) ( Fragment: `sum(foo or vector(1))`, }, }, + IsConditional: true, }, { Type: utils.AggregateSource, @@ -2793,6 +2313,7 @@ sum by (region, target, colo_name) ( Fragment: "sum(foo or vector(1))", }, }, + IsConditional: true, }, }, }, @@ -2800,12 +2321,10 @@ sum by (region, target, colo_name) ( expr: `(sum(foo or vector(2)) > 0) != 2`, output: []utils.Source{ { - Type: utils.AggregateSource, - Returns: promParser.ValueTypeVector, - Operation: "sum", - Selectors: []*promParser.VectorSelector{ - mustParseVector(`foo`, 5), - }, + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 5), FixedLabels: true, ExcludeReason: map[string]utils.ExcludedLabel{ "": { @@ -2813,6 +2332,7 @@ sum by (region, target, colo_name) ( Fragment: `sum(foo or vector(2))`, }, }, + IsConditional: true, }, { Type: utils.AggregateSource, @@ -2828,6 +2348,188 @@ sum by (region, target, colo_name) ( Fragment: "sum(foo or vector(2))", }, }, + IsConditional: true, + }, + }, + }, + { + expr: ` +(sum(sometimes{foo!="bar"} or vector(0))) +or +((bob > 10) or sum(foo) or vector(1))`, + output: []utils.Source{ + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `sometimes{foo!="bar"}`, 6), + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation that removes all labels.", + Fragment: `sum(sometimes{foo!="bar"} or vector(0)))`, // FIXME bogus ) + }, + }, + }, + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + AlwaysReturns: true, + ReturnedNumbers: []float64{0}, + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation that removes all labels.", + Fragment: `sum(sometimes{foo!="bar"} or vector(0)))`, // FIXME bogus ) + }, + }, + }, + { + Type: utils.SelectorSource, + Operation: promParser.CardManyToMany.String(), + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bob`, 48), + IsConditional: true, + }, + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `foo`, 65), + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation that removes all labels.", + Fragment: `sum(foo)`, + }, + }, + }, + { + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "vector", + AlwaysReturns: true, + ReturnedNumbers: []float64{1}, + FixedLabels: true, + Call: mustParse[*promParser.Call](t, "vector(1)", 73), + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Calling `vector()` will return a vector value with no labels.", + Fragment: "vector(1)", + }, + }, + }, + }, + }, + { + expr: ` +( + sum(sometimes{foo!="bar"}) + or + vector(1) +) and ( + ((bob > 10) or sum(bar)) + or + notfound > 0 +)`, + output: []utils.Source{ + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `sometimes{foo!="bar"}`, 8), + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation that removes all labels.", + Fragment: `sum(sometimes{foo!="bar"})`, + }, + }, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Operation: promParser.CardManyToMany.String(), + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bob`, 57), + IsConditional: true, + }, + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 74), + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation that removes all labels.", + Fragment: `sum(bar))`, // FIXME bogus ) + }, + }, + }, + { + Type: utils.SelectorSource, + Operation: promParser.CardManyToMany.String(), + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `notfound`, 85), + IsConditional: true, + }, + }, + }, + { + Type: utils.FuncSource, + Returns: promParser.ValueTypeVector, + Operation: "vector", + AlwaysReturns: true, + ReturnedNumbers: []float64{1}, + FixedLabels: true, + Call: mustParse[*promParser.Call](t, "vector(1)", 36), + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Calling `vector()` will return a vector value with no labels.", + Fragment: "vector(1)", + }, + }, + Joins: []utils.Source{ + { + Type: utils.SelectorSource, + Operation: promParser.CardManyToMany.String(), + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `bob`, 57), + IsConditional: true, + }, + { + Type: utils.AggregateSource, + Returns: promParser.ValueTypeVector, + Operation: "sum", + Selector: mustParse[*promParser.VectorSelector](t, `bar`, 74), + FixedLabels: true, + ExcludeReason: map[string]utils.ExcludedLabel{ + "": { + Reason: "Query is using aggregation that removes all labels.", + Fragment: `sum(bar))`, // FIXME bogus ) + }, + }, + }, + { + Type: utils.SelectorSource, + Operation: promParser.CardManyToMany.String(), + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, `notfound`, 85), + IsConditional: true, + }, + }, + }, + }, + }, + { + expr: "foo offset 5m > 5", + output: []utils.Source{ + { + Type: utils.SelectorSource, + Returns: promParser.ValueTypeVector, + Selector: mustParse[*promParser.VectorSelector](t, "foo offset 5m", 0), + IsConditional: true, }, }, },