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.
This commit is contained in:
nicbaz 2020-06-23 22:50:33 +02:00 committed by GitHub
parent a560b4788e
commit 774f7ca1c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 19 additions and 1 deletions

View file

@ -1480,7 +1480,7 @@ func TestExecSuccess(t *testing.T) {
resultExpected := []netstorage.Result{r} resultExpected := []netstorage.Result{r}
f(q, resultExpected) f(q, resultExpected)
}) })
t.Run(`label_replace(mismatch)`, func(t *testing.T) { t.Run(`label_replace(nonexisting_src)`, func(t *testing.T) {
t.Parallel() t.Parallel()
q := `label_replace(time(), "__name__", "x${1}y", "foo", ".+")` q := `label_replace(time(), "__name__", "x${1}y", "foo", ".+")`
r := netstorage.Result{ r := netstorage.Result{
@ -1491,6 +1491,21 @@ func TestExecSuccess(t *testing.T) {
resultExpected := []netstorage.Result{r} resultExpected := []netstorage.Result{r}
f(q, resultExpected) 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.Run(`label_replace(match)`, func(t *testing.T) {
t.Parallel() t.Parallel()
q := `label_replace(time(), "__name__", "x${1}y", "foo", ".*")` q := `label_replace(time(), "__name__", "x${1}y", "foo", ".*")`

View file

@ -1219,6 +1219,9 @@ func labelReplace(tss []*timeseries, srcLabel string, r *regexp.Regexp, dstLabel
mn := &ts.MetricName mn := &ts.MetricName
dstValue := getDstValue(mn, dstLabel) dstValue := getDstValue(mn, dstLabel)
srcValue := mn.GetTagValue(srcLabel) srcValue := mn.GetTagValue(srcLabel)
if !r.Match(srcValue) {
continue
}
b := r.ReplaceAll(srcValue, replacementBytes) b := r.ReplaceAll(srcValue, replacementBytes)
*dstValue = append((*dstValue)[:0], b...) *dstValue = append((*dstValue)[:0], b...)
if len(b) == 0 { if len(b) == 0 {