diff --git a/app/vmselect/graphite/transform.go b/app/vmselect/graphite/transform.go index 9ab4134599..fb78da773b 100644 --- a/app/vmselect/graphite/transform.go +++ b/app/vmselect/graphite/transform.go @@ -3599,6 +3599,17 @@ func groupSeriesByNodes(ss []*series, nodes []graphiteql.Expr) map[string][]*ser return m } +func getAbsoluteNodeIndex(index, size int) int { + // handling the negative index case + if index < 0 && index+size > 0 { + index = index + size + } + if index >= size || index < 0 { + return -1 + } + return index +} + func getNameFromNodes(name string, tags map[string]string, nodes []graphiteql.Expr) string { if len(nodes) == 0 { return "" @@ -3609,7 +3620,7 @@ func getNameFromNodes(name string, tags map[string]string, nodes []graphiteql.Ex for _, node := range nodes { switch t := node.(type) { case *graphiteql.NumberExpr: - if n := int(t.N); n >= 0 && n < len(parts) { + if n := getAbsoluteNodeIndex(int(t.N), len(parts)); n >= 0 { dstParts = append(dstParts, parts[n]) } case *graphiteql.StringExpr: diff --git a/app/vmselect/graphite/transform_test.go b/app/vmselect/graphite/transform_test.go index 388d84b785..22b918010f 100644 --- a/app/vmselect/graphite/transform_test.go +++ b/app/vmselect/graphite/transform_test.go @@ -79,3 +79,17 @@ func TestGraphiteToGolangRegexpReplace(t *testing.T) { f(`a\d+`, `a\d+`) f(`\1f\\oo\2`, `$1f\\oo$2`) } + +func TestGetAbsoluteNodeIndex(t *testing.T) { + f := func(index, size, expectedIndex int) { + t.Helper() + absoluteIndex := getAbsoluteNodeIndex(index, size) + if absoluteIndex != expectedIndex { + t.Fatalf("unexpected result for getAbsoluteNodeIndex(%d, %d); got %d; want %d", index, size, expectedIndex, absoluteIndex) + } + } + f(1, 1, -1) + f(0, 1, 0) + f(-1, 3, 2) + f(-3, 1, -1) +} diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index aaa01c9d20..2710228bd7 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -28,6 +28,7 @@ The sandbox cluster installation is running under the constant load generated by ## tip +* FEATURE: [vmselect](https://docs.victoriametrics.com/vmselect.html): adding support for negative index in Graphite groupByNode/aliasByNode. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5581). * FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): add support for [DataDog v2 data ingestion protocol](https://docs.datadoghq.com/api/latest/metrics/#submit-metrics). See [these docs](https://docs.victoriametrics.com/#how-to-send-data-from-datadog-agent) and [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4451). * FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): expose ability to set OAuth2 endpoint parameters per each `-remoteWrite.url` via the command-line flag `-remoteWrite.oauth2.endpointParams`. See [these docs](https://docs.victoriametrics.com/vmagent.html#advanced-usage). Thanks to @mhill-holoplot for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5427). * FEATURE: [vmalert](https://docs.victoriametrics.com/vmagent.html): expose ability to set OAuth2 endpoint parameters via the following command-line flags: