Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/querying/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Comment thread
bboreham marked this conversation as resolved.

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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
52 changes: 50 additions & 2 deletions web/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -703,6 +708,11 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
if names == nil {
names = []string{}
}

if len(names) >= limit {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this check be len(names) == limit instead of >=? In this case the returned elements can be equal to the limit and also contain all elements in the database, but the response will still contain a warning. The same is used on the other two endpoints

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean len(names) > limit?
I opened #14116 to fix that.
Thanks and don't hesitate to open an issue for such "issues":)

names = names[:limit]
warnings = warnings.Add(errors.New("results truncated due to limit"))
}
return apiFuncResult{names, nil, warnings, nil}
Comment thread
bboreham marked this conversation as resolved.
}

Expand All @@ -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")
Expand Down Expand Up @@ -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}
}

Expand All @@ -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")
Expand Down Expand Up @@ -860,11 +885,17 @@ func (api *API) series(r *http.Request) (result apiFuncResult) {
}

metrics := []labels.Labels{}

warnings := set.Warnings()

for set.Next() {
metrics = append(metrics, set.At().Labels())
}

warnings := set.Warnings()
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}
}
Expand Down Expand Up @@ -1868,3 +1899,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
}
31 changes: 31 additions & 0 deletions web/api/v1/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,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,
Expand Down Expand Up @@ -2671,6 +2681,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,
Expand Down Expand Up @@ -2810,6 +2833,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__"},
},
}...)
}

Expand Down