mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-25 05:34:05 -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.
|
||||
- `start=<rfc3339 | unix_timestamp>`: Start 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
|
||||
`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.
|
||||
- `match[]=<series_selector>`: Repeated series selector argument that selects the
|
||||
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.
|
||||
|
@ -356,6 +358,7 @@ URL query parameters:
|
|||
- `end=<rfc3339 | unix_timestamp>`: End timestamp. Optional.
|
||||
- `match[]=<series_selector>`: Repeated series selector argument that selects the
|
||||
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.
|
||||
|
|
|
@ -644,6 +644,11 @@ func returnAPIError(err error) *apiError {
|
|||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return invalidParamError(err, "start")
|
||||
|
@ -703,6 +708,11 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
|
|||
if names == nil {
|
||||
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}
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
}
|
||||
|
||||
limit, err := parseLimitParam(r.FormValue("limit"))
|
||||
if err != nil {
|
||||
return invalidParamError(err, "limit")
|
||||
}
|
||||
|
||||
start, err := parseTimeParam(r, "start", MinTime)
|
||||
if err != nil {
|
||||
return invalidParamError(err, "start")
|
||||
|
@ -783,6 +798,11 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) {
|
|||
|
||||
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}
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
}
|
||||
|
||||
limit, err := parseLimitParam(r.FormValue("limit"))
|
||||
if err != nil {
|
||||
return invalidParamError(err, "limit")
|
||||
}
|
||||
|
||||
start, err := parseTimeParam(r, "start", MinTime)
|
||||
if err != nil {
|
||||
return invalidParamError(err, "start")
|
||||
|
@ -860,11 +885,17 @@ func (api *API) series(r *http.Request) (result apiFuncResult) {
|
|||
}
|
||||
|
||||
metrics := []labels.Labels{}
|
||||
for set.Next() {
|
||||
metrics = append(metrics, set.At().Labels())
|
||||
}
|
||||
|
||||
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 {
|
||||
return apiFuncResult{nil, returnAPIError(set.Err()), warnings, closer}
|
||||
}
|
||||
|
@ -1867,3 +1898,20 @@ OUTER:
|
|||
}
|
||||
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.
|
||||
{
|
||||
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,
|
||||
errType: errorBadData,
|
||||
|
@ -2660,6 +2670,19 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
|||
"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.
|
||||
{
|
||||
endpoint: api.labelNames,
|
||||
|
@ -2799,6 +2822,14 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
|||
},
|
||||
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