diff --git a/README.md b/README.md index 85675eb54..ff7fb3fc2 100644 --- a/README.md +++ b/README.md @@ -566,6 +566,7 @@ VictoriaMetrics supports the following handlers from [Graphite Tags API](https:/ * [/tags/findSeries](https://graphite.readthedocs.io/en/stable/tags.html#exploring-tags) * [/tags/autoComplete/tags](https://graphite.readthedocs.io/en/stable/tags.html#auto-complete-support) * [/tags/autoComplete/values](https://graphite.readthedocs.io/en/stable/tags.html#auto-complete-support) +* [/tags/delSeries](https://graphite.readthedocs.io/en/stable/tags.html#removing-series-from-the-tagdb) ## How to build from sources diff --git a/app/vmselect/graphite/tags_api.go b/app/vmselect/graphite/tags_api.go index 9591df4bc..ba46aeb2d 100644 --- a/app/vmselect/graphite/tags_api.go +++ b/app/vmselect/graphite/tags_api.go @@ -19,6 +19,52 @@ import ( "github.com/VictoriaMetrics/metrics" ) +// TagsDelSeriesHandler implements /tags/delSeries handler. +// +// See https://graphite.readthedocs.io/en/stable/tags.html#removing-series-from-the-tagdb +func TagsDelSeriesHandler(startTime time.Time, w http.ResponseWriter, r *http.Request) error { + if err := r.ParseForm(); err != nil { + return fmt.Errorf("cannot parse form values: %w", err) + } + paths := r.Form["path"] + totalDeleted := 0 + var row graphiteparser.Row + var tagsPool []graphiteparser.Tag + ct := time.Now().UnixNano() / 1e6 + for _, path := range paths { + var err error + tagsPool, err = row.UnmarshalMetricAndTags(path, tagsPool[:0]) + if err != nil { + return fmt.Errorf("cannot parse path=%q: %w", path, err) + } + tfs := make([]storage.TagFilter, 0, 1+len(row.Tags)) + tfs = append(tfs, storage.TagFilter{ + Key: nil, + Value: []byte(row.Metric), + }) + for _, tag := range row.Tags { + tfs = append(tfs, storage.TagFilter{ + Key: []byte(tag.Key), + Value: []byte(tag.Value), + }) + } + sq := storage.NewSearchQuery(0, ct, [][]storage.TagFilter{tfs}) + n, err := netstorage.DeleteSeries(sq) + if err != nil { + return fmt.Errorf("cannot delete series for %q: %w", sq, err) + } + totalDeleted += n + } + + w.Header().Set("Content-Type", "application/json; charset=utf-8") + if totalDeleted > 0 { + fmt.Fprintf(w, "true") + } else { + fmt.Fprintf(w, "false") + } + return nil +} + // TagsTagSeriesHandler implements /tags/tagSeries handler. // // See https://graphite.readthedocs.io/en/stable/tags.html#adding-series-to-the-tagdb diff --git a/app/vmselect/main.go b/app/vmselect/main.go index ff7a9d0da..57dee7a9f 100644 --- a/app/vmselect/main.go +++ b/app/vmselect/main.go @@ -319,6 +319,14 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool { return true } return true + case "/tags/delSeries": + graphiteTagsDelSeriesRequests.Inc() + if err := graphite.TagsDelSeriesHandler(startTime, w, r); err != nil { + graphiteTagsDelSeriesErrors.Inc() + httpserver.Errorf(w, r, "error in %q: %s", r.URL.Path, err) + return true + } + return true case "/api/v1/rules": // Return dumb placeholder rulesRequests.Inc() @@ -453,6 +461,9 @@ var ( graphiteTagsAutoCompleteValuesRequests = metrics.NewCounter(`vm_http_requests_total{path="/tags/autoComplete/values"}`) graphiteTagsAutoCompleteValuesErrors = metrics.NewCounter(`vm_http_request_errors_total{path="/tags/autoComplete/values"}`) + graphiteTagsDelSeriesRequests = metrics.NewCounter(`vm_http_requests_total{path="/tags/delSeries"}`) + graphiteTagsDelSeriesErrors = metrics.NewCounter(`vm_http_request_errors_total{path="/tags/delSeries"}`) + rulesRequests = metrics.NewCounter(`vm_http_requests_total{path="/api/v1/rules"}`) alertsRequests = metrics.NewCounter(`vm_http_requests_total{path="/api/v1/alerts"}`) metadataRequests = metrics.NewCounter(`vm_http_requests_total{path="/api/v1/metadata"}`) diff --git a/docs/Single-server-VictoriaMetrics.md b/docs/Single-server-VictoriaMetrics.md index 85675eb54..ff7fb3fc2 100644 --- a/docs/Single-server-VictoriaMetrics.md +++ b/docs/Single-server-VictoriaMetrics.md @@ -566,6 +566,7 @@ VictoriaMetrics supports the following handlers from [Graphite Tags API](https:/ * [/tags/findSeries](https://graphite.readthedocs.io/en/stable/tags.html#exploring-tags) * [/tags/autoComplete/tags](https://graphite.readthedocs.io/en/stable/tags.html#auto-complete-support) * [/tags/autoComplete/values](https://graphite.readthedocs.io/en/stable/tags.html#auto-complete-support) +* [/tags/delSeries](https://graphite.readthedocs.io/en/stable/tags.html#removing-series-from-the-tagdb) ## How to build from sources