From 46c5c0772c3ed5c653be21d40829a41d3ba4a903 Mon Sep 17 00:00:00 2001 From: nicbaz Date: Tue, 23 Jun 2020 22:50:33 +0200 Subject: [PATCH] vmselect: fix label_replace when mismatch (#579) As per documentation on `label_replace` function: "If the regular expression doesn't match then the timeseries is returned unchanged". Currently this behavior is not enforced, if a regexp on an existing tag doesn't match then the tag value is copied as-is in the destination tag. This fix first checks that the regular expression matches the source tag before applying anything. Given the current implementation, this fix also changes the behavior of the **MetricsQL** `label_transform` function which does not document this behavior at the moment. --- app/vmselect/promql/exec_test.go | 17 ++++++++++++++++- app/vmselect/promql/transform.go | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go index 937d3a81b..1975584c1 100644 --- a/app/vmselect/promql/exec_test.go +++ b/app/vmselect/promql/exec_test.go @@ -1490,7 +1490,7 @@ func TestExecSuccess(t *testing.T) { resultExpected := []netstorage.Result{r} f(q, resultExpected) }) - t.Run(`label_replace(mismatch)`, func(t *testing.T) { + t.Run(`label_replace(nonexisting_src)`, func(t *testing.T) { t.Parallel() q := `label_replace(time(), "__name__", "x${1}y", "foo", ".+")` r := netstorage.Result{ @@ -1501,6 +1501,21 @@ func TestExecSuccess(t *testing.T) { resultExpected := []netstorage.Result{r} f(q, resultExpected) }) + t.Run(`label_replace(mismatch)`, func(t *testing.T) { + t.Parallel() + q := `label_replace(label_set(time(), "foo", "foobar"), "__name__", "x${1}y", "foo", "bar(.+)")` + r := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{1000, 1200, 1400, 1600, 1800, 2000}, + Timestamps: timestampsExpected, + } + r.MetricName.Tags = []storage.Tag{{ + Key: []byte("foo"), + Value: []byte("foobar"), + }} + resultExpected := []netstorage.Result{r} + f(q, resultExpected) + }) t.Run(`label_replace(match)`, func(t *testing.T) { t.Parallel() q := `label_replace(time(), "__name__", "x${1}y", "foo", ".*")` diff --git a/app/vmselect/promql/transform.go b/app/vmselect/promql/transform.go index b08f9e8a4..1f0f85812 100644 --- a/app/vmselect/promql/transform.go +++ b/app/vmselect/promql/transform.go @@ -1219,6 +1219,9 @@ func labelReplace(tss []*timeseries, srcLabel string, r *regexp.Regexp, dstLabel mn := &ts.MetricName dstValue := getDstValue(mn, dstLabel) srcValue := mn.GetTagValue(srcLabel) + if !r.Match(srcValue) { + continue + } b := r.ReplaceAll(srcValue, replacementBytes) *dstValue = append((*dstValue)[:0], b...) if len(b) == 0 {