diff --git a/README.md b/README.md index 9fa9498cb..b6423e919 100644 --- a/README.md +++ b/README.md @@ -416,9 +416,15 @@ The `/api/v1/export` endpoint should return the following response: Data sent to VictoriaMetrics via `Graphite plaintext protocol` may be read via the following APIs: * [Graphite API](#graphite-api-usage) -* [Prometheus querying API](#prometheus-querying-api-usage). VictoriaMetrics supports `__graphite__` pseudo-label for selecting time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). VictoriaMetrics also supports [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function for extracting the given groups from Graphite metric name. +* [Prometheus querying API](#prometheus-querying-api-usage). See also [selecting Graphite metrics](#selecting-graphite-metrics). * [go-graphite/carbonapi](https://github.com/go-graphite/carbonapi/blob/main/cmd/carbonapi/carbonapi.example.victoriametrics.yaml) +## Selecting Graphite metrics + +VictoriaMetrics supports `__graphite__` pseudo-label for selecting time series with Graphite-compatible filters in [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html). For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster and it is easier to use when migrating from Graphite to VictoriaMetrics. See [docs for Graphite paths and wildcards](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). VictoriaMetrics also supports [label_graphite_group](https://docs.victoriametrics.com/MetricsQL.html#label_graphite_group) function for extracting the given groups from Graphite metric name. + +The `__graphite__` pseudo-label supports e.g. alternate regexp filters such as `(value1|...|valueN)`. They are transparently converted to `{value1,...,valueN}` syntax [used in Graphite](https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards). This allows using [multi-value template variables in Grafana](https://grafana.com/docs/grafana/latest/variables/formatting-multi-value-variables/) inside `__graphite__` pseudo-label. For example, Grafana expands `{__graphite__=~"foo.($bar).baz"}` into `{__graphite__=~"foo.(x|y).baz"}` if `$bar` template variable contains `x` and `y` values. In this case the query is automatically converted into `{__graphite__=~"foo.{x,y}.baz"}` before execution. + ## How to send data from OpenTSDB-compatible agents VictoriaMetrics supports [telnet put protocol](http://opentsdb.net/docs/build/html/api_telnet/put.html) @@ -559,8 +565,7 @@ VictoriaMetrics accepts optional query args: `extra_label==== 0 { + n = bytes.IndexByte(x, '|') + if n < 0 { + dst = append(dst, x...) + break + } + dst = append(dst, x[:n]...) + x = x[n+1:] + dst = append(dst, ',') + } + dst = append(dst, '}') + } +} + func (s *Storage) searchGraphitePaths(tr TimeRange, qHead, qTail []byte, maxPaths int, deadline uint64) ([]string, error) { n := bytes.IndexAny(qTail, "*[{") if n < 0 { diff --git a/lib/storage/storage_test.go b/lib/storage/storage_test.go index 975ebe7bc..c58788a83 100644 --- a/lib/storage/storage_test.go +++ b/lib/storage/storage_test.go @@ -14,6 +14,24 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/uint64set" ) +func TestReplaceAlternateRegexpsWithGraphiteWildcards(t *testing.T) { + f := func(q, resultExpected string) { + t.Helper() + result := replaceAlternateRegexpsWithGraphiteWildcards([]byte(q)) + if string(result) != resultExpected { + t.Fatalf("unexpected result for %s\ngot\n%s\nwant\n%s", q, result, resultExpected) + } + } + f("", "") + f("foo", "foo") + f("foo(bar", "foo(bar") + f("foo.(bar|baz", "foo.(bar|baz") + f("foo.(bar).x", "foo.{bar}.x") + f("foo.(bar|baz).*.{x,y}", "foo.{bar,baz}.*.{x,y}") + f("foo.(bar|baz).*.{x,y}(z|aa)", "foo.{bar,baz}.*.{x,y}{z,aa}") + f("foo(.*)", "foo*") +} + func TestGetRegexpForGraphiteNodeQuery(t *testing.T) { f := func(q, expectedRegexp string) { t.Helper()