app/vmselect/graphite: accept and enforce extra_label in all the Graphite APIs

This commit is contained in:
Aliaksandr Valialkin 2021-03-23 15:14:29 +02:00
parent 27bb614016
commit d1e773266f
3 changed files with 30 additions and 7 deletions

View File

@ -32,13 +32,17 @@ func TagsDelSeriesHandler(startTime time.Time, at *auth.Token, w http.ResponseWr
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, at *auth.Token, w http.ResponseWr
Value: []byte(tag.Value), Value: []byte(tag.Value),
}) })
} }
tfs = append(tfs, etfs...)
sq := storage.NewSearchQuery(at.AccountID, at.ProjectID, 0, ct, [][]storage.TagFilter{tfs}) sq := storage.NewSearchQuery(at.AccountID, at.ProjectID, 0, ct, [][]storage.TagFilter{tfs})
n, err := netstorage.DeleteSeries(at, sq, deadline) n, err := netstorage.DeleteSeries(at, sq, deadline)
if err != nil { if err != nil {
@ -178,8 +183,12 @@ func TagsAutoCompleteValuesHandler(startTime time.Time, at *auth.Token, w http.R
exprs := r.Form["expr"] exprs := r.Form["expr"]
var tagValues []string var tagValues []string
denyPartialResponse := searchutils.GetDenyPartialResponse(r) denyPartialResponse := searchutils.GetDenyPartialResponse(r)
etfs, err := searchutils.GetEnforcedTagFiltersFromRequest(r)
if err != nil {
return fmt.Errorf("cannot setup tag filters: %w", err)
}
isPartial := false isPartial := false
if len(exprs) == 0 { 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
@ -190,7 +199,7 @@ func TagsAutoCompleteValuesHandler(startTime time.Time, at *auth.Token, w http.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, at, exprs) sq, err := getSearchQueryForExprs(startTime, at, etfs, exprs)
if err != nil { if err != nil {
return err return err
} }
@ -261,9 +270,13 @@ func TagsAutoCompleteTagsHandler(startTime time.Time, at *auth.Token, w http.Res
tagPrefix := r.FormValue("tagPrefix") tagPrefix := r.FormValue("tagPrefix")
exprs := r.Form["expr"] exprs := r.Form["expr"]
denyPartialResponse := searchutils.GetDenyPartialResponse(r) denyPartialResponse := searchutils.GetDenyPartialResponse(r)
etfs, err := searchutils.GetEnforcedTagFiltersFromRequest(r)
if err != nil {
return fmt.Errorf("cannot setup tag filters: %w", err)
}
var labels []string var labels []string
isPartial := false isPartial := false
if len(exprs) == 0 { 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.
@ -275,7 +288,7 @@ func TagsAutoCompleteTagsHandler(startTime time.Time, at *auth.Token, w http.Res
} }
} else { } else {
// Slow path: use netstorage.SearchMetricNames for applying `expr` filters. // Slow path: use netstorage.SearchMetricNames for applying `expr` filters.
sq, err := getSearchQueryForExprs(startTime, at, exprs) sq, err := getSearchQueryForExprs(startTime, at, etfs, exprs)
if err != nil { if err != nil {
return err return err
} }
@ -339,7 +352,11 @@ func TagsFindSeriesHandler(startTime time.Time, at *auth.Token, w http.ResponseW
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, at, exprs) etfs, err := searchutils.GetEnforcedTagFiltersFromRequest(r)
if err != nil {
return fmt.Errorf("cannot setup tag filters: %w", err)
}
sq, err := getSearchQueryForExprs(startTime, at, etfs, exprs)
if err != nil { if err != nil {
return err return err
} }
@ -467,12 +484,13 @@ func getInt(r *http.Request, argName string) (int, error) {
return n, nil return n, nil
} }
func getSearchQueryForExprs(startTime time.Time, at *auth.Token, exprs []string) (*storage.SearchQuery, error) { func getSearchQueryForExprs(startTime time.Time, at *auth.Token, 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(at.AccountID, at.ProjectID, 0, ct, [][]storage.TagFilter{tfs}) sq := storage.NewSearchQuery(at.AccountID, at.ProjectID, 0, ct, [][]storage.TagFilter{tfs})
return sq, nil return sq, nil
} }

View File

@ -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.

View File

@ -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.