app/vmselect/promql: properly keep metric names when optimized path is used for aggregate function calculations

For example, `sum(rate(...) keep_metric_names) by (__name__)` didn't leave the original metric name because of this issue.

This is a follup-up for 1bdc71d917

Udates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/949
This commit is contained in:
Aliaksandr Valialkin 2022-01-17 15:27:00 +02:00
parent 34da060cd1
commit cc76174387
No known key found for this signature in database
GPG key ID: A72BEC6CD3D0DED1
2 changed files with 49 additions and 2 deletions

View file

@ -496,6 +496,9 @@ func getRollupExprArg(arg metricsql.Expr) *metricsql.RollupExpr {
return &reNew
}
// expr may contain:
// - rollupFunc(m) if iafc is nil
// - aggrFunc(rollupFunc(m)) if iafc isn't nil
func evalRollupFunc(ec *EvalConfig, funcName string, rf rollupFunc, expr metricsql.Expr, re *metricsql.RollupExpr, iafc *incrementalAggrFuncContext) ([]*timeseries, error) {
if re.At == nil {
return evalRollupFuncWithoutAt(ec, funcName, rf, expr, re, iafc)
@ -641,6 +644,15 @@ func evalRollupFuncWithSubquery(ec *EvalConfig, funcName string, rf rollupFunc,
}
func getKeepMetricNames(expr metricsql.Expr) bool {
if ae, ok := expr.(*metricsql.AggrFuncExpr); ok {
// Extract rollupFunc(...) from aggrFunc(rollupFunc(...)).
// This case is possible when optimized aggrFunc calculations are used
// such as `sum(rate(...))`
if len(ae.Args) != 1 {
return false
}
expr = ae.Args[0]
}
if fe, ok := expr.(*metricsql.FuncExpr); ok {
return fe.KeepMetricNames
}

View file

@ -1029,6 +1029,17 @@ func TestExecSuccess(t *testing.T) {
resultExpected := []netstorage.Result{r}
f(q, resultExpected)
})
t.Run("time() @ end() offset 10m", func(t *testing.T) {
t.Parallel()
q := `time() @ end() offset 10m`
r := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{1400, 1400, 1400, 1400, 1400, 1400},
Timestamps: timestampsExpected,
}
resultExpected := []netstorage.Result{r}
f(q, resultExpected)
})
t.Run("time() @ (end()-10m)", func(t *testing.T) {
t.Parallel()
q := `time() @ (end()-10m)`
@ -6229,18 +6240,42 @@ func TestExecSuccess(t *testing.T) {
})
t.Run(`rate(time())`, func(t *testing.T) {
t.Parallel()
q := `rate(alias(time(), "foo"))`
q := `rate(label_set(alias(time(), "foo"), "x", "y"))`
r := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{1, 1, 1, 1, 1, 1},
Timestamps: timestampsExpected,
}
r.MetricName.Tags = []storage.Tag{
{
Key: []byte("x"),
Value: []byte("y"),
},
}
resultExpected := []netstorage.Result{r}
f(q, resultExpected)
})
t.Run(`rate(time()) keep_metric_names`, func(t *testing.T) {
t.Parallel()
q := `rate(alias(time(), "foo")) keep_metric_names`
q := `rate(label_set(alias(time(), "foo"), "x", "y")) keep_metric_names`
r := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{1, 1, 1, 1, 1, 1},
Timestamps: timestampsExpected,
}
r.MetricName.MetricGroup = []byte("foo")
r.MetricName.Tags = []storage.Tag{
{
Key: []byte("x"),
Value: []byte("y"),
},
}
resultExpected := []netstorage.Result{r}
f(q, resultExpected)
})
t.Run(`sum(rate(time()) keep_metric_names) by (__name__)`, func(t *testing.T) {
t.Parallel()
q := `sum(rate(label_set(alias(time(), "foo"), "x", "y")) keep_metric_names) by (__name__)`
r := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{1, 1, 1, 1, 1, 1},