mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
web/api: add limit param on series, labels, label-values (#13396)
Support limit parameter in queries to restrict output data to the specified size, on the following endpoints: /api/v1/series /api/v1/labels /api/v1/label/:name:/values Signed-off-by: Pranshu Srivastava <rexagod@gmail.com> Signed-off-by: Kartikay <kartikay_2101ce32@iitp.ac.in>
This commit is contained in:
parent
ab9b770aea
commit
8736772053
|
@ -256,6 +256,7 @@ URL query parameters:
|
||||||
series to return. At least one `match[]` argument must be provided.
|
series to return. At least one `match[]` argument must be provided.
|
||||||
- `start=<rfc3339 | unix_timestamp>`: Start timestamp.
|
- `start=<rfc3339 | unix_timestamp>`: Start timestamp.
|
||||||
- `end=<rfc3339 | unix_timestamp>`: End timestamp.
|
- `end=<rfc3339 | unix_timestamp>`: End timestamp.
|
||||||
|
- `limit=<number>`: Maximum number of returned series. Optional.
|
||||||
|
|
||||||
You can URL-encode these parameters directly in the request body by using the `POST` method and
|
You can URL-encode these parameters directly in the request body by using the `POST` method and
|
||||||
`Content-Type: application/x-www-form-urlencoded` header. This is useful when specifying a large
|
`Content-Type: application/x-www-form-urlencoded` header. This is useful when specifying a large
|
||||||
|
@ -306,6 +307,7 @@ URL query parameters:
|
||||||
- `end=<rfc3339 | unix_timestamp>`: End timestamp. Optional.
|
- `end=<rfc3339 | unix_timestamp>`: End timestamp. Optional.
|
||||||
- `match[]=<series_selector>`: Repeated series selector argument that selects the
|
- `match[]=<series_selector>`: Repeated series selector argument that selects the
|
||||||
series from which to read the label names. Optional.
|
series from which to read the label names. Optional.
|
||||||
|
- `limit=<number>`: Maximum number of returned series. Optional.
|
||||||
|
|
||||||
|
|
||||||
The `data` section of the JSON response is a list of string label names.
|
The `data` section of the JSON response is a list of string label names.
|
||||||
|
@ -356,6 +358,7 @@ URL query parameters:
|
||||||
- `end=<rfc3339 | unix_timestamp>`: End timestamp. Optional.
|
- `end=<rfc3339 | unix_timestamp>`: End timestamp. Optional.
|
||||||
- `match[]=<series_selector>`: Repeated series selector argument that selects the
|
- `match[]=<series_selector>`: Repeated series selector argument that selects the
|
||||||
series from which to read the label values. Optional.
|
series from which to read the label values. Optional.
|
||||||
|
- `limit=<number>`: Maximum number of returned series. Optional.
|
||||||
|
|
||||||
|
|
||||||
The `data` section of the JSON response is a list of string label values.
|
The `data` section of the JSON response is a list of string label values.
|
||||||
|
|
|
@ -644,6 +644,11 @@ func returnAPIError(err error) *apiError {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) labelNames(r *http.Request) apiFuncResult {
|
func (api *API) labelNames(r *http.Request) apiFuncResult {
|
||||||
|
limit, err := parseLimitParam(r.FormValue("limit"))
|
||||||
|
if err != nil {
|
||||||
|
return invalidParamError(err, "limit")
|
||||||
|
}
|
||||||
|
|
||||||
start, err := parseTimeParam(r, "start", MinTime)
|
start, err := parseTimeParam(r, "start", MinTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return invalidParamError(err, "start")
|
return invalidParamError(err, "start")
|
||||||
|
@ -703,6 +708,11 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
|
||||||
if names == nil {
|
if names == nil {
|
||||||
names = []string{}
|
names = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(names) >= limit {
|
||||||
|
names = names[:limit]
|
||||||
|
warnings = warnings.Add(errors.New("results truncated due to limit"))
|
||||||
|
}
|
||||||
return apiFuncResult{names, nil, warnings, nil}
|
return apiFuncResult{names, nil, warnings, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,6 +724,11 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) {
|
||||||
return apiFuncResult{nil, &apiError{errorBadData, fmt.Errorf("invalid label name: %q", name)}, nil, nil}
|
return apiFuncResult{nil, &apiError{errorBadData, fmt.Errorf("invalid label name: %q", name)}, nil, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
limit, err := parseLimitParam(r.FormValue("limit"))
|
||||||
|
if err != nil {
|
||||||
|
return invalidParamError(err, "limit")
|
||||||
|
}
|
||||||
|
|
||||||
start, err := parseTimeParam(r, "start", MinTime)
|
start, err := parseTimeParam(r, "start", MinTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return invalidParamError(err, "start")
|
return invalidParamError(err, "start")
|
||||||
|
@ -783,6 +798,11 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) {
|
||||||
|
|
||||||
slices.Sort(vals)
|
slices.Sort(vals)
|
||||||
|
|
||||||
|
if len(vals) >= limit {
|
||||||
|
vals = vals[:limit]
|
||||||
|
warnings = warnings.Add(errors.New("results truncated due to limit"))
|
||||||
|
}
|
||||||
|
|
||||||
return apiFuncResult{vals, nil, warnings, closer}
|
return apiFuncResult{vals, nil, warnings, closer}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,6 +829,11 @@ func (api *API) series(r *http.Request) (result apiFuncResult) {
|
||||||
return apiFuncResult{nil, &apiError{errorBadData, errors.New("no match[] parameter provided")}, nil, nil}
|
return apiFuncResult{nil, &apiError{errorBadData, errors.New("no match[] parameter provided")}, nil, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
limit, err := parseLimitParam(r.FormValue("limit"))
|
||||||
|
if err != nil {
|
||||||
|
return invalidParamError(err, "limit")
|
||||||
|
}
|
||||||
|
|
||||||
start, err := parseTimeParam(r, "start", MinTime)
|
start, err := parseTimeParam(r, "start", MinTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return invalidParamError(err, "start")
|
return invalidParamError(err, "start")
|
||||||
|
@ -860,11 +885,17 @@ func (api *API) series(r *http.Request) (result apiFuncResult) {
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics := []labels.Labels{}
|
metrics := []labels.Labels{}
|
||||||
for set.Next() {
|
|
||||||
metrics = append(metrics, set.At().Labels())
|
|
||||||
}
|
|
||||||
|
|
||||||
warnings := set.Warnings()
|
warnings := set.Warnings()
|
||||||
|
|
||||||
|
for set.Next() {
|
||||||
|
metrics = append(metrics, set.At().Labels())
|
||||||
|
|
||||||
|
if len(metrics) >= limit {
|
||||||
|
warnings.Add(errors.New("results truncated due to limit"))
|
||||||
|
return apiFuncResult{metrics, nil, warnings, closer}
|
||||||
|
}
|
||||||
|
}
|
||||||
if set.Err() != nil {
|
if set.Err() != nil {
|
||||||
return apiFuncResult{nil, returnAPIError(set.Err()), warnings, closer}
|
return apiFuncResult{nil, returnAPIError(set.Err()), warnings, closer}
|
||||||
}
|
}
|
||||||
|
@ -1867,3 +1898,20 @@ OUTER:
|
||||||
}
|
}
|
||||||
return matcherSets, nil
|
return matcherSets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseLimitParam(limitStr string) (limit int, err error) {
|
||||||
|
limit = math.MaxInt
|
||||||
|
if limitStr == "" {
|
||||||
|
return limit, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
limit, err = strconv.Atoi(limitStr)
|
||||||
|
if err != nil {
|
||||||
|
return limit, err
|
||||||
|
}
|
||||||
|
if limit <= 0 {
|
||||||
|
return limit, errors.New("limit must be positive")
|
||||||
|
}
|
||||||
|
|
||||||
|
return limit, nil
|
||||||
|
}
|
||||||
|
|
|
@ -1389,6 +1389,16 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Missing match[] query params in series requests.
|
// Missing match[] query params in series requests.
|
||||||
|
{
|
||||||
|
endpoint: api.series,
|
||||||
|
query: url.Values{
|
||||||
|
"match[]": []string{"test_metric1"},
|
||||||
|
"limit": []string{"1"},
|
||||||
|
},
|
||||||
|
response: []labels.Labels{
|
||||||
|
labels.FromStrings("__name__", "test_metric1", "foo", "bar"),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
endpoint: api.series,
|
endpoint: api.series,
|
||||||
errType: errorBadData,
|
errType: errorBadData,
|
||||||
|
@ -2660,6 +2670,19 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
||||||
"boo",
|
"boo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
endpoint: api.labelValues,
|
||||||
|
params: map[string]string{
|
||||||
|
"name": "foo",
|
||||||
|
},
|
||||||
|
query: url.Values{
|
||||||
|
"match[]": []string{"test_metric4"},
|
||||||
|
"limit": []string{"1"},
|
||||||
|
},
|
||||||
|
response: []string{
|
||||||
|
"bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
// Label names.
|
// Label names.
|
||||||
{
|
{
|
||||||
endpoint: api.labelNames,
|
endpoint: api.labelNames,
|
||||||
|
@ -2799,6 +2822,14 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
||||||
},
|
},
|
||||||
response: []string{"__name__", "foo"},
|
response: []string{"__name__", "foo"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
endpoint: api.labelNames,
|
||||||
|
query: url.Values{
|
||||||
|
"match[]": []string{"test_metric2"},
|
||||||
|
"limit": []string{"1"},
|
||||||
|
},
|
||||||
|
response: []string{"__name__"},
|
||||||
|
},
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue