mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-24 05:04:05 -08:00
web/api: add GET and DELETE /series endpoints
This commit is contained in:
parent
0acd44b0e3
commit
7bb7e565a4
|
@ -93,6 +93,9 @@ func (api *API) Register(r *route.Router) {
|
|||
r.Get("/query_range", instr("query_range", api.queryRange))
|
||||
|
||||
r.Get("/label/:name/values", instr("label_values", api.labelValues))
|
||||
|
||||
r.Get("/series", instr("series", api.series))
|
||||
r.Del("/series", instr("drop_series", api.dropSeries))
|
||||
}
|
||||
|
||||
type queryData struct {
|
||||
|
@ -180,6 +183,60 @@ func (api *API) labelValues(r *http.Request) (interface{}, *apiError) {
|
|||
return vals, nil
|
||||
}
|
||||
|
||||
func (api *API) series(r *http.Request) (interface{}, *apiError) {
|
||||
r.ParseForm()
|
||||
if len(r.Form["match[]"]) == 0 {
|
||||
return nil, &apiError{errorBadData, fmt.Errorf("no match[] parameter provided")}
|
||||
}
|
||||
fps := map[clientmodel.Fingerprint]struct{}{}
|
||||
|
||||
for _, lm := range r.Form["match[]"] {
|
||||
matchers, err := promql.ParseMetricSelector(lm)
|
||||
if err != nil {
|
||||
return nil, &apiError{errorBadData, err}
|
||||
}
|
||||
for _, fp := range api.Storage.FingerprintsForLabelMatchers(matchers) {
|
||||
fps[fp] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
metrics := make([]clientmodel.Metric, 0, len(fps))
|
||||
for fp := range fps {
|
||||
if met := api.Storage.MetricForFingerprint(fp).Metric; met != nil {
|
||||
metrics = append(metrics, met)
|
||||
}
|
||||
}
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
func (api *API) dropSeries(r *http.Request) (interface{}, *apiError) {
|
||||
r.ParseForm()
|
||||
if len(r.Form["match[]"]) == 0 {
|
||||
return nil, &apiError{errorBadData, fmt.Errorf("no match[] parameter provided")}
|
||||
}
|
||||
fps := map[clientmodel.Fingerprint]struct{}{}
|
||||
|
||||
for _, lm := range r.Form["match[]"] {
|
||||
matchers, err := promql.ParseMetricSelector(lm)
|
||||
if err != nil {
|
||||
return nil, &apiError{errorBadData, err}
|
||||
}
|
||||
for _, fp := range api.Storage.FingerprintsForLabelMatchers(matchers) {
|
||||
fps[fp] = struct{}{}
|
||||
}
|
||||
}
|
||||
for fp := range fps {
|
||||
api.Storage.DropMetricsForFingerprints(fp)
|
||||
}
|
||||
|
||||
res := struct {
|
||||
NumDeleted int `json:"numDeleted"`
|
||||
}{
|
||||
NumDeleted: len(fps),
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func respond(w http.ResponseWriter, data interface{}) {
|
||||
w.WriteHeader(200)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
|
|
@ -195,6 +195,94 @@ func TestEndpoints(t *testing.T) {
|
|||
},
|
||||
errType: errorBadData,
|
||||
},
|
||||
{
|
||||
endpoint: api.series,
|
||||
query: url.Values{
|
||||
"match[]": []string{`test_metric2`},
|
||||
},
|
||||
response: []clientmodel.Metric{
|
||||
{
|
||||
"__name__": "test_metric2",
|
||||
"foo": "boo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
endpoint: api.series,
|
||||
query: url.Values{
|
||||
"match[]": []string{`test_metric1{foo=~"o$"}`},
|
||||
},
|
||||
response: []clientmodel.Metric{
|
||||
{
|
||||
"__name__": "test_metric1",
|
||||
"foo": "boo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
endpoint: api.series,
|
||||
query: url.Values{
|
||||
"match[]": []string{`test_metric1{foo=~"o$"}`, `test_metric1{foo=~"o$"}`},
|
||||
},
|
||||
response: []clientmodel.Metric{
|
||||
{
|
||||
"__name__": "test_metric1",
|
||||
"foo": "boo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
endpoint: api.series,
|
||||
query: url.Values{
|
||||
"match[]": []string{`test_metric1{foo=~"o$"}`, `none`},
|
||||
},
|
||||
response: []clientmodel.Metric{
|
||||
{
|
||||
"__name__": "test_metric1",
|
||||
"foo": "boo",
|
||||
},
|
||||
},
|
||||
},
|
||||
// Missing match[] query params in series requests.
|
||||
{
|
||||
endpoint: api.series,
|
||||
errType: errorBadData,
|
||||
},
|
||||
{
|
||||
endpoint: api.dropSeries,
|
||||
errType: errorBadData,
|
||||
},
|
||||
// The following tests delete time series from the test storage. They
|
||||
// must remain at the end and are fixed in their order.
|
||||
{
|
||||
endpoint: api.dropSeries,
|
||||
query: url.Values{
|
||||
"match[]": []string{`test_metric1{foo=~"o$"}`},
|
||||
},
|
||||
response: struct {
|
||||
NumDeleted int `json:"numDeleted"`
|
||||
}{1},
|
||||
},
|
||||
{
|
||||
endpoint: api.series,
|
||||
query: url.Values{
|
||||
"match[]": []string{`test_metric1`},
|
||||
},
|
||||
response: []clientmodel.Metric{
|
||||
{
|
||||
"__name__": "test_metric1",
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
endpoint: api.dropSeries,
|
||||
query: url.Values{
|
||||
"match[]": []string{`{__name__=~".*"}`},
|
||||
},
|
||||
response: struct {
|
||||
NumDeleted int `json:"numDeleted"`
|
||||
}{2},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
@ -227,6 +315,8 @@ func TestEndpoints(t *testing.T) {
|
|||
if !reflect.DeepEqual(resp, test.response) {
|
||||
t.Fatalf("Response does not match, expected:\n%#v\ngot:\n%#v", test.response, resp)
|
||||
}
|
||||
// Ensure that removed metrics are unindexed before the next request.
|
||||
suite.Storage().WaitForIndexing()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue