diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go index 2034ded54..2c4ddd203 100644 --- a/app/vmselect/promql/exec_test.go +++ b/app/vmselect/promql/exec_test.go @@ -1302,6 +1302,44 @@ func TestExecSuccess(t *testing.T) { resultExpected := []netstorage.Result{r} f(q, resultExpected) }) + t.Run(`label_value()`, func(t *testing.T) { + t.Parallel() + q := `with ( + x = ( + label_set(time(), "foo", "123.456", "__name__", "aaa"), + label_set(-time(), "foo", "bar", "__name__", "bbb"), + label_set(-time(), "__name__", "bxs"), + label_set(-time(), "foo", "45", "bar", "xs"), + ) + ) + sort(x + label_value(x, "foo"))` + r1 := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{-955, -1155, -1355, -1555, -1755, -1955}, + Timestamps: timestampsExpected, + } + r1.MetricName.Tags = []storage.Tag{ + { + Key: []byte("bar"), + Value: []byte("xs"), + }, + { + Key: []byte("foo"), + Value: []byte("45"), + }, + } + r2 := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{1123.456, 1323.456, 1523.456, 1723.456, 1923.456, 2123.456}, + Timestamps: timestampsExpected, + } + r2.MetricName.Tags = []storage.Tag{{ + Key: []byte("foo"), + Value: []byte("123.456"), + }} + resultExpected := []netstorage.Result{r1, r2} + f(q, resultExpected) + }) t.Run(`label_transform(mismatch)`, func(t *testing.T) { t.Parallel() q := `label_transform(time(), "__name__", "foobar", "xx")` diff --git a/app/vmselect/promql/transform.go b/app/vmselect/promql/transform.go index 2fe0b02d5..db830cbbd 100644 --- a/app/vmselect/promql/transform.go +++ b/app/vmselect/promql/transform.go @@ -63,6 +63,7 @@ var transformFuncs = map[string]transformFunc{ "label_copy": transformLabelCopy, "label_move": transformLabelMove, "label_transform": transformLabelTransform, + "label_value": transformLabelValue, "union": transformUnion, "": transformUnion, // empty func is a synonim to union "keep_last_value": transformKeepLastValue, @@ -881,6 +882,31 @@ func labelReplace(tss []*timeseries, srcLabel string, r *regexp.Regexp, dstLabel return tss, nil } +func transformLabelValue(tfa *transformFuncArg) ([]*timeseries, error) { + args := tfa.args + if err := expectTransformArgsNum(args, 2); err != nil { + return nil, err + } + labelName, err := getString(args[1], 1) + if err != nil { + return nil, fmt.Errorf("cannot get label name: %s", err) + } + rvs := args[0] + for _, ts := range rvs { + ts.MetricName.ResetMetricGroup() + labelValue := ts.MetricName.GetTagValue(labelName) + v, err := strconv.ParseFloat(string(labelValue), 64) + if err != nil { + v = nan + } + values := ts.Values + for i := range values { + values[i] = v + } + } + return rvs, nil +} + func transformLn(v float64) float64 { return math.Log(v) }