mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-03 16:21:14 +01:00
app/vmselect/graphite: accept and enforce extra_label
in all the Graphite APIs
This commit is contained in:
parent
b521d1d4f2
commit
331a6a2015
@ -605,6 +605,10 @@ VictoriaMetrics supports the following Graphite APIs, which are needed for [Grap
|
|||||||
|
|
||||||
All the Graphite handlers can be pre-pended with `/graphite` prefix. For example, both `/graphite/metrics/find` and `/metrics/find` should work.
|
All the Graphite handlers can be pre-pended with `/graphite` prefix. For example, both `/graphite/metrics/find` and `/metrics/find` should work.
|
||||||
|
|
||||||
|
VictoriaMetrics accepts optional `extra_label=<label_name>=<label_value>` query arg for all the Graphite APIs. This arg can be used for limiting the scope of time series
|
||||||
|
visible to the given tenant. It is expected that the `extra_label` query arg is automatically set by auth proxy sitting in front of VictoriaMetrics.
|
||||||
|
[Contact us](mailto:sales@victoriametrics.com) if you need assistance with such a proxy.
|
||||||
|
|
||||||
VictoriaMetrics supports `__graphite__` pseudo-label for filtering time series with Graphite-compatible filters in [MetricsQL](https://victoriametrics.github.io/MetricsQL.html).
|
VictoriaMetrics supports `__graphite__` pseudo-label for filtering time series with Graphite-compatible filters in [MetricsQL](https://victoriametrics.github.io/MetricsQL.html).
|
||||||
For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster
|
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.
|
and it is easier to use when migrating from Graphite to VictoriaMetrics.
|
||||||
|
@ -32,13 +32,17 @@ func TagsDelSeriesHandler(startTime time.Time, w http.ResponseWriter, r *http.Re
|
|||||||
var row graphiteparser.Row
|
var row graphiteparser.Row
|
||||||
var tagsPool []graphiteparser.Tag
|
var tagsPool []graphiteparser.Tag
|
||||||
ct := startTime.UnixNano() / 1e6
|
ct := startTime.UnixNano() / 1e6
|
||||||
|
etfs, err := searchutils.GetEnforcedTagFiltersFromRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot setup tag filters: %w", err)
|
||||||
|
}
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
var err error
|
var err error
|
||||||
tagsPool, err = row.UnmarshalMetricAndTags(path, tagsPool[:0])
|
tagsPool, err = row.UnmarshalMetricAndTags(path, tagsPool[:0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot parse path=%q: %w", path, err)
|
return fmt.Errorf("cannot parse path=%q: %w", path, err)
|
||||||
}
|
}
|
||||||
tfs := make([]storage.TagFilter, 0, 1+len(row.Tags))
|
tfs := make([]storage.TagFilter, 0, 1+len(row.Tags)+len(etfs))
|
||||||
tfs = append(tfs, storage.TagFilter{
|
tfs = append(tfs, storage.TagFilter{
|
||||||
Key: nil,
|
Key: nil,
|
||||||
Value: []byte(row.Metric),
|
Value: []byte(row.Metric),
|
||||||
@ -49,6 +53,7 @@ func TagsDelSeriesHandler(startTime time.Time, w http.ResponseWriter, r *http.Re
|
|||||||
Value: []byte(tag.Value),
|
Value: []byte(tag.Value),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
tfs = append(tfs, etfs...)
|
||||||
sq := storage.NewSearchQuery(0, ct, [][]storage.TagFilter{tfs})
|
sq := storage.NewSearchQuery(0, ct, [][]storage.TagFilter{tfs})
|
||||||
n, err := netstorage.DeleteSeries(sq, deadline)
|
n, err := netstorage.DeleteSeries(sq, deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -176,7 +181,11 @@ func TagsAutoCompleteValuesHandler(startTime time.Time, w http.ResponseWriter, r
|
|||||||
valuePrefix := r.FormValue("valuePrefix")
|
valuePrefix := r.FormValue("valuePrefix")
|
||||||
exprs := r.Form["expr"]
|
exprs := r.Form["expr"]
|
||||||
var tagValues []string
|
var tagValues []string
|
||||||
if len(exprs) == 0 {
|
etfs, err := searchutils.GetEnforcedTagFiltersFromRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot setup tag filters: %w", err)
|
||||||
|
}
|
||||||
|
if len(exprs) == 0 && len(etfs) == 0 {
|
||||||
// Fast path: there are no `expr` filters, so use netstorage.GetGraphiteTagValues.
|
// Fast path: there are no `expr` filters, so use netstorage.GetGraphiteTagValues.
|
||||||
// Escape special chars in tagPrefix as Graphite does.
|
// Escape special chars in tagPrefix as Graphite does.
|
||||||
// See https://github.com/graphite-project/graphite-web/blob/3ad279df5cb90b211953e39161df416e54a84948/webapp/graphite/tags/base.py#L228
|
// See https://github.com/graphite-project/graphite-web/blob/3ad279df5cb90b211953e39161df416e54a84948/webapp/graphite/tags/base.py#L228
|
||||||
@ -187,7 +196,7 @@ func TagsAutoCompleteValuesHandler(startTime time.Time, w http.ResponseWriter, r
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Slow path: use netstorage.SearchMetricNames for applying `expr` filters.
|
// Slow path: use netstorage.SearchMetricNames for applying `expr` filters.
|
||||||
sq, err := getSearchQueryForExprs(startTime, exprs)
|
sq, err := getSearchQueryForExprs(startTime, etfs, exprs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -257,7 +266,11 @@ func TagsAutoCompleteTagsHandler(startTime time.Time, w http.ResponseWriter, r *
|
|||||||
tagPrefix := r.FormValue("tagPrefix")
|
tagPrefix := r.FormValue("tagPrefix")
|
||||||
exprs := r.Form["expr"]
|
exprs := r.Form["expr"]
|
||||||
var labels []string
|
var labels []string
|
||||||
if len(exprs) == 0 {
|
etfs, err := searchutils.GetEnforcedTagFiltersFromRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot setup tag filters: %w", err)
|
||||||
|
}
|
||||||
|
if len(exprs) == 0 && len(etfs) == 0 {
|
||||||
// Fast path: there are no `expr` filters, so use netstorage.GetGraphiteTags.
|
// Fast path: there are no `expr` filters, so use netstorage.GetGraphiteTags.
|
||||||
|
|
||||||
// Escape special chars in tagPrefix as Graphite does.
|
// Escape special chars in tagPrefix as Graphite does.
|
||||||
@ -269,7 +282,7 @@ func TagsAutoCompleteTagsHandler(startTime time.Time, w http.ResponseWriter, r *
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Slow path: use netstorage.SearchMetricNames for applying `expr` filters.
|
// Slow path: use netstorage.SearchMetricNames for applying `expr` filters.
|
||||||
sq, err := getSearchQueryForExprs(startTime, exprs)
|
sq, err := getSearchQueryForExprs(startTime, etfs, exprs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -332,7 +345,11 @@ func TagsFindSeriesHandler(startTime time.Time, w http.ResponseWriter, r *http.R
|
|||||||
if len(exprs) == 0 {
|
if len(exprs) == 0 {
|
||||||
return fmt.Errorf("expecting at least one `expr` query arg")
|
return fmt.Errorf("expecting at least one `expr` query arg")
|
||||||
}
|
}
|
||||||
sq, err := getSearchQueryForExprs(startTime, exprs)
|
etfs, err := searchutils.GetEnforcedTagFiltersFromRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot setup tag filters: %w", err)
|
||||||
|
}
|
||||||
|
sq, err := getSearchQueryForExprs(startTime, etfs, exprs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -457,12 +474,13 @@ func getInt(r *http.Request, argName string) (int, error) {
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSearchQueryForExprs(startTime time.Time, exprs []string) (*storage.SearchQuery, error) {
|
func getSearchQueryForExprs(startTime time.Time, etfs []storage.TagFilter, exprs []string) (*storage.SearchQuery, error) {
|
||||||
tfs, err := exprsToTagFilters(exprs)
|
tfs, err := exprsToTagFilters(exprs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ct := startTime.UnixNano() / 1e6
|
ct := startTime.UnixNano() / 1e6
|
||||||
|
tfs = append(tfs, etfs...)
|
||||||
sq := storage.NewSearchQuery(0, ct, [][]storage.TagFilter{tfs})
|
sq := storage.NewSearchQuery(0, ct, [][]storage.TagFilter{tfs})
|
||||||
return sq, nil
|
return sq, nil
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
* `process_resident_memory_shared_bytes` - RSS share for memory shared with other processes (aka shared memory). This share can be freed by the OS at any time, so it must be ignored by OOM killer.
|
* `process_resident_memory_shared_bytes` - RSS share for memory shared with other processes (aka shared memory). This share can be freed by the OS at any time, so it must be ignored by OOM killer.
|
||||||
* `process_resident_memory_peak_bytes` - peak RSS usage for the process.
|
* `process_resident_memory_peak_bytes` - peak RSS usage for the process.
|
||||||
* `process_virtual_memory_peak_bytes` - peak virtual memory usage for the process.
|
* `process_virtual_memory_peak_bytes` - peak virtual memory usage for the process.
|
||||||
|
* FEATURE: accept and enforce `extra_label=<label_name>=<label_value>` query arg at [Graphite APIs](https://victoriametrics.github.io/#graphite-api-usage).
|
||||||
|
|
||||||
* BUGFIX: prevent from infinite loop on `{__graphite__="..."}` filters when a metric name contains `*`, `{` or `[` chars.
|
* BUGFIX: prevent from infinite loop on `{__graphite__="..."}` filters when a metric name contains `*`, `{` or `[` chars.
|
||||||
* BUGFIX: prevent from infinite loop in `/metrics/find` and `/metrics/expand` [Graphite Metrics API handlers](https://victoriametrics.github.io/#graphite-metrics-api-usage) when they match metric names or labels with `*`, `{` or `[` chars.
|
* BUGFIX: prevent from infinite loop in `/metrics/find` and `/metrics/expand` [Graphite Metrics API handlers](https://victoriametrics.github.io/#graphite-metrics-api-usage) when they match metric names or labels with `*`, `{` or `[` chars.
|
||||||
|
@ -605,6 +605,10 @@ VictoriaMetrics supports the following Graphite APIs, which are needed for [Grap
|
|||||||
|
|
||||||
All the Graphite handlers can be pre-pended with `/graphite` prefix. For example, both `/graphite/metrics/find` and `/metrics/find` should work.
|
All the Graphite handlers can be pre-pended with `/graphite` prefix. For example, both `/graphite/metrics/find` and `/metrics/find` should work.
|
||||||
|
|
||||||
|
VictoriaMetrics accepts optional `extra_label=<label_name>=<label_value>` query arg for all the Graphite APIs. This arg can be used for limiting the scope of time series
|
||||||
|
visible to the given tenant. It is expected that the `extra_label` query arg is automatically set by auth proxy sitting in front of VictoriaMetrics.
|
||||||
|
[Contact us](mailto:sales@victoriametrics.com) if you need assistance with such a proxy.
|
||||||
|
|
||||||
VictoriaMetrics supports `__graphite__` pseudo-label for filtering time series with Graphite-compatible filters in [MetricsQL](https://victoriametrics.github.io/MetricsQL.html).
|
VictoriaMetrics supports `__graphite__` pseudo-label for filtering time series with Graphite-compatible filters in [MetricsQL](https://victoriametrics.github.io/MetricsQL.html).
|
||||||
For example, `{__graphite__="foo.*.bar"}` is equivalent to `{__name__=~"foo[.][^.]*[.]bar"}`, but it works faster
|
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.
|
and it is easier to use when migrating from Graphite to VictoriaMetrics.
|
||||||
|
Loading…
Reference in New Issue
Block a user