diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go index d6d22735e4..17a2b6ef50 100644 --- a/app/vmselect/promql/exec_test.go +++ b/app/vmselect/promql/exec_test.go @@ -1274,6 +1274,12 @@ func TestExecSuccess(t *testing.T) { Values: []float64{1000, 1200, 1400, 1600, 1800, 2000}, Timestamps: timestampsExpected, } + r.MetricName.Tags = []storage.Tag{ + { + Key: []byte("tagname"), + Value: []byte("foobar"), + }, + } resultExpected := []netstorage.Result{r} f(q, resultExpected) }) @@ -1288,6 +1294,12 @@ func TestExecSuccess(t *testing.T) { Values: []float64{1000, 1200, 1400, 1600, 1800, 2000}, Timestamps: timestampsExpected, } + r.MetricName.Tags = []storage.Tag{ + { + Key: []byte("tagname"), + Value: []byte("foobar"), + }, + } resultExpected := []netstorage.Result{r} f(q, resultExpected) }) diff --git a/app/vmselect/promql/transform.go b/app/vmselect/promql/transform.go index 8165802c37..4402772b70 100644 --- a/app/vmselect/promql/transform.go +++ b/app/vmselect/promql/transform.go @@ -1446,11 +1446,12 @@ func transformLabelCopyExt(tfa *transformFuncArg, removeSrcLabels bool) ([]*time for i, srcLabel := range srcLabels { dstLabel := dstLabels[i] value := mn.GetTagValue(srcLabel) + if len(value) == 0 { + // Do not remove destination label if the source label doesn't exist. + continue + } dstValue := getDstValue(mn, dstLabel) *dstValue = append((*dstValue)[:0], value...) - if len(value) == 0 { - mn.RemoveTag(dstLabel) - } if removeSrcLabels && srcLabel != dstLabel { mn.RemoveTag(srcLabel) } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3c29577ee7..0da0a1e4dd 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,7 @@ * FEATURE: vminsert and vmagent: add `-sortLabels` command-line flag for sorting metric labels before pushing them to `vmstorage`. This should reduce the size of `MetricName -> internal_series_id` cache (aka `vm_cache_size_bytes{type="storage/tsid"}`) when ingesting samples for the same time series with distinct order of labels. For example, `foo{k1="v1",k2="v2"}` and `foo{k2="v2",k1="v1"}` represent a single time series. * FEATURE: allow specifying label value alongside label name for the `others sum` time series returned from `topk_*` and `bottomk_*` functions from [MetricsQL](https://victoriametrics.github.io/MetricsQL.html). For example, `topk_avg(3, max(process_resident_memory_bytes) by (instance), "instance=other_sum")` would return top 3 series from `max(process_resident_memory_bytes) by (instance)` plus a series containing of the sum of other series. The `others sum` series will have `{instance="other_sum"}` label. +* FEATURE: do not delete `dst_label` when applying `label_copy(q, "src_label", "dst_label")` and `label_move(q, "src_label", "dst_label")` to series without `src_label` and with non-empty `dst_label`. See more details at [MetricsQL docs](https://victoriametrics.github.io/MetricsQL.html). * FEATURE: update Go builder from `v1.16.2` to `v1.16.3`. This should fix [these issues](https://github.com/golang/go/issues?q=milestone%3AGo1.16.3+label%3ACherryPickApproved). * FEATURE: vmagent: add support for `follow_redirects` option to `scrape_configs` section in the same way as [Prometheus 2.26 does](https://github.com/prometheus/prometheus/pull/8546). * FEATURE: vmagent: add support for `authorization` section in `-promscrape.config` in the same way as [Prometheus 2.26 does](https://github.com/prometheus/prometheus/pull/8512). diff --git a/docs/MetricsQL.md b/docs/MetricsQL.md index 53be6f107c..514816a369 100644 --- a/docs/MetricsQL.md +++ b/docs/MetricsQL.md @@ -55,19 +55,19 @@ This functionality can be tried at [an editable Grafana dashboard](http://play-g - `ru(freeResources, maxResources)` function for returning resource utilization percentage in the range `0% - 100%`. For instance, `ru(node_memory_MemFree_bytes, node_memory_MemTotal_bytes)` returns memory utilization over [node_exporter](https://github.com/prometheus/node_exporter) metrics. - `ttf(slowlyChangingFreeResources)` function for returning the time in seconds when the given `slowlyChangingFreeResources` expression reaches zero. For instance, `ttf(node_filesystem_avail_byte)` returns the time to storage space exhaustion. This function may be useful for capacity planning. - Functions for label manipulation: - - `alias(q, name)` for setting metric name across all the time series `q`. - - `label_set(q, label1, value1, ... labelN, valueN)` for setting the given values for the given labels on `q`. - - `label_map(q, label, srcValue1, dstValue1, ... srcValueN, dstValueN)` for mapping `label` values from `src*` to `dst*`. - - `label_uppercase(q, label1, ... labelN)` for uppercasing values for the given labels. - - `label_lowercase(q, label2, ... labelN)` for lowercasing value for the given labels. - - `label_del(q, label1, ... labelN)` for deleting the given labels from `q`. - - `label_keep(q, label1, ... labelN)` for deleting all the labels except the given labels from `q`. - - `label_copy(q, src_label1, dst_label1, ... src_labelN, dst_labelN)` for copying label values from `src_*` to `dst_*`. - - `label_move(q, src_label1, dst_label1, ... src_labelN, dst_labelN)` for moving label values from `src_*` to `dst_*`. - - `label_transform(q, label, regexp, replacement)` for replacing all the `regexp` occurences with `replacement` in the `label` values from `q`. - - `label_value(q, label)` - returns numeric values for the given `label` from `q`. + - `alias(q, name)` for setting metric name across all the time series `q`. For example, `alias(foo, "bar")` would give `bar` name to all the `foo` series. + - `label_set(q, label1, value1, ... labelN, valueN)` for setting the given values for the given labels on `q`. For example, `label_set(foo, "bar", "baz")` would add `{bar="baz"}` label to all the `foo` series. + - `label_map(q, label, srcValue1, dstValue1, ... srcValueN, dstValueN)` for mapping `label` values from `src*` to `dst*`. For example, `label_map(foo, "instance", "127.0.0.1", "locahost")` would rename `foo{instance="127.0.0.1"}` to `foo{instance="localhost"}`. + - `label_uppercase(q, label1, ... labelN)` for uppercasing values for the given labels. For example, `label_uppercase(foo, "instance")` would transform `foo{instance="bar"}` to `foo{instance="BAR"}`. + - `label_lowercase(q, label2, ... labelN)` for lowercasing value for the given labels. For example, `label_lowercase(foo, "instance")` would transform `foo{instance="BAR"}` to `foo{instance="bar"}`. + - `label_del(q, label1, ... labelN)` for deleting the given labels from `q`. For example, `label_del(foo, "bar")` would delete `bar` label from all the `foo` series. + - `label_keep(q, label1, ... labelN)` for deleting all the labels except the given labels from `q`. For example, `label_keep(foo, "bar")` would delete all the labels except `bar` from `foo` series. + - `label_copy(q, src_label1, dst_label1, ... src_labelN, dst_labelN)` for copying label values from `src_*` to `dst_*`. If `src_label` is empty, then `dst_label` is left untouched. For example, `label_copy(foo, "bar", baz")` would transform `foo{bar="x"}` to `foo{bar="x",baz="x"}`. + - `label_move(q, src_label1, dst_label1, ... src_labelN, dst_labelN)` for moving label values from `src_*` to `dst_*`. If `src_label` is empty, then `dst_label` is left untouched. For example, `label_move(foo, 'bar", "baz")` would transform `foo{bar="x"}` to `foo{bax="x"}`. + - `label_transform(q, label, regexp, replacement)` for replacing all the `regexp` occurences with `replacement` in the `label` values from `q`. For example, `label_transform(foo, "bar", "-", "_")` would transform `foo{bar="a-b-c"}` to `foo{bar="a_b_c"}`. + - `label_value(q, label)` - returns numeric values for the given `label` from `q`. For example, if `label_value(foo, "bar")` is applied to `foo{bar="1.234"}`, then it will return a time series `foo{bar="1.234"}` with `1.234` value. - `label_match(q, label, regexp)` and `label_mismatch(q, label, regexp)` for filtering time series with labels matching (or not matching) the given regexps. -- `sort_by_label(q, label1, ... labelN)` and `sort_by_label_desc(q, label1, ... labelN)` for sorting time series by the given set of labels. +- `sort_by_label(q, label1, ... labelN)` and `sort_by_label_desc(q, label1, ... labelN)` for sorting time series by the given set of labels. For example, `sort_by_label(foo, "bar")` would sort `foo` series by values of the label `bar` in these series. - `step()` function for returning the step in seconds used in the query. - `start()` and `end()` functions for returning the start and end timestamps of the `[start ... end]` range used in the query. - `integrate(m[d])` for returning integral over the given duration `d` for the given metric `m`.