Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

web/api add limit param #13396

Merged
merged 9 commits into from
Feb 29, 2024
Merged

web/api add limit param #13396

merged 9 commits into from
Feb 29, 2024

Conversation

kartikaysaxena
Copy link
Contributor

In continuation to the PR #12823

Signed-off-by: Kartikay <kartikay_2101ce32@iitp.ac.in>
Signed-off-by: Kartikay <kartikay_2101ce32@iitp.ac.in>
@kartikaysaxena
Copy link
Contributor Author

Hey @GiedriusS! Can you please take a look at this pull request?

@beorn7
Copy link
Member

beorn7 commented Jan 17, 2024

Requesting review from @bboreham as the author of the original proposal #12795 .


func parseLimitParam(limitStr string) (limit int, err error) {
limit = math.MaxInt
if limitStr != "" {
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably better to return early:

if limitStr == "" {
  return limit, nil
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Member

Choose a reason for hiding this comment

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

So now you don't need to check != "". This is a Go style point: the code moves further to the left (is less indented) so is a little easier to read.

Copy link
Member

@bboreham bboreham left a comment

Choose a reason for hiding this comment

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

Thanks for this PR. The code is nice and simple.

As an enhancement we could pass in the limit to the code that computes results, so we can stop early rather than creating the full result then truncating it. However I think it would be fine to merge this and then make it more efficient.

web/api/v1/api.go Outdated Show resolved Hide resolved
web/api/v1/api.go Outdated Show resolved Hide resolved
Signed-off-by: Kartikay <kartikay_2101ce32@iitp.ac.in>
@bboreham
Copy link
Member

It just occurred to me: the caller might like to know if the results were truncated.

@yeya24
Copy link
Contributor

yeya24 commented Feb 8, 2024

Any plan to move this forward?

@kartikaysaxena
Copy link
Contributor Author

It just occurred to me: the caller might like to know if the results were truncated.

You mean should I add a warning to the response if the results were truncated because of the limit?

@bboreham
Copy link
Member

bboreham commented Feb 9, 2024

You mean should I add a warning to the response if the results were truncated because of the limit?

Sounds reasonable.

Signed-off-by: Kartikay <kartikay_2101ce32@iitp.ac.in>
Signed-off-by: Kartikay <kartikay_2101ce32@iitp.ac.in>
@kartikaysaxena
Copy link
Contributor Author

kartikaysaxena commented Feb 9, 2024

curl -g 'http://localhost:9090/api/v1/series?match[]=up&match[]=go_goroutines{job="example-app"}'

{"status":"success","data":[{"__name__":"go_goroutines","instance":"localhost:9090","job":"example-app"},{"__name__":"up","instance":"localhost:8080","job":"example-app"},{"__name__":"up","instance":"localhost:9090","job":"example-app"}]}%

curl -g 'http://localhost:9090/api/v1/series?match[]=up&match[]=go_goroutines{job="example-app"}&limit=1'

{"status":"success","data":[{"__name__":"go_goroutines","instance":"localhost:9090","job":"example-app"}],"warnings":["results truncated due to limit"]}%

It now shows the warnings in the response when the results are truncated

@@ -783,6 +792,14 @@ func (api *API) labelValues(r *http.Request) (result apiFuncResult) {

slices.Sort(vals)

limit, err := parseLimitParam(r.FormValue("limit"))
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we move this before we actually fetch data? So that we don't throw a 400 error after we finish fetching label values

@@ -860,8 +877,19 @@ func (api *API) series(r *http.Request) (result apiFuncResult) {
}

metrics := []labels.Labels{}

limit, err := parseLimitParam(r.FormValue("limit"))
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

Signed-off-by: Kartikay <kartikay_2101ce32@iitp.ac.in>
@yeya24
Copy link
Contributor

yeya24 commented Feb 9, 2024

It might be out of scope of this pr.
Now the limit applies at the API layer, which is after fetching all requested data. Should we consider adding limit as part of the storage interface so that we can return less data from underlying TSDB?

For Series we can probably do it via SelectHints, but I am unsure about label names and label values API.

Signed-off-by: Kartikay <kartikay_2101ce32@iitp.ac.in>
@darshanime
Copy link
Contributor

the limit applies at the API layer, which is after fetching all requested data

Since we check for limits within the Next() loop, we don't really fetch all the series data? We do fetch all the labels though, but those are cheap enough due to an index read.
@bboreham wdyt?

@yeya24
Copy link
Contributor

yeya24 commented Feb 10, 2024

@darshanime I think you are correct. However, that requires the underlying implementation to support streaming.
If the implementation doesn't support streaming, for example the remote read querier, or other implementations in downstream projects like Cortex or Thanos, then we overfetch data.

Having limit as part of the hints might help such usecases.

@bboreham
Copy link
Member

Since we check for limits within the Next() loop, we don't really fetch all the series data? We do fetch all the labels though, but those are cheap enough due to an index read.

In some code paths the results are sorted before that loop. Sorting is O(N log N).

And that is not the only place where the limit could be applied.

@kartikaysaxena
Copy link
Contributor Author

I think we may move this forward and then further iterate on it, at least for a start.

Copy link
Member

@bboreham bboreham left a comment

Choose a reason for hiding this comment

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

Thanks, the code seems nearly done.

Since there was a mistake in the handling of warnings, you should add a test for that case.
Also, ideally, a test for an invalid limit parameter.

docs/querying/api.md Show resolved Hide resolved

func parseLimitParam(limitStr string) (limit int, err error) {
limit = math.MaxInt
if limitStr != "" {
Copy link
Member

Choose a reason for hiding this comment

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

So now you don't need to check != "". This is a Go style point: the code moves further to the left (is less indented) so is a little easier to read.

if len(vals) >= limit {
vals = vals[:limit]
warnings = annotations.New().Add(errors.New("results truncated due to limit"))
return apiFuncResult{vals, nil, warnings, closer}
Copy link
Member

Choose a reason for hiding this comment

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

This line seems unnecessary.

if len(names) >= limit {
names = names[:limit]
warnings := annotations.New().Add(errors.New("results truncated due to limit"))
return apiFuncResult{names, nil, warnings, nil}
Copy link
Member

Choose a reason for hiding this comment

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

This line seems unnecessary, since it is identical to the next line.

web/api/v1/api.go Outdated Show resolved Hide resolved
web/api/v1/api.go Outdated Show resolved Hide resolved
@yeya24
Copy link
Contributor

yeya24 commented Feb 14, 2024

I think we may move this forward and then further iterate on it, at least for a start.

Thanks. Yeah I think it is a good start.

Signed-off-by: Kartikay <kartikay_2101ce32@iitp.ac.in>
@kartikaysaxena
Copy link
Contributor Author

Hey @bboreham, sorry for the delay. I was busy with some academic engagements at my university, so I have made some changes; can you please take a look at them? Thanks for your guidance.

Copy link
Member

@bboreham bboreham left a comment

Choose a reason for hiding this comment

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

I think this is very close now. Couple of comments remain from my previous review.

web/api/v1/api.go Outdated Show resolved Hide resolved
Signed-off-by: Kartikay <kartikay_2101ce32@iitp.ac.in>
@kartikaysaxena
Copy link
Contributor Author

Was busy due to university minors, suggestions are implemented now, PTAL @bboreham

Copy link
Member

@bboreham bboreham left a comment

Choose a reason for hiding this comment

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

Thanks, I think we can merge this now and iterate based on experience.

@bboreham bboreham merged commit 8736772 into prometheus:main Feb 29, 2024
24 checks passed
@bboreham
Copy link
Member

BTW I added @rexagod as co-author in sign-off, since the original code came from #12823

@@ -703,6 +708,11 @@ func (api *API) labelNames(r *http.Request) apiFuncResult {
if names == nil {
names = []string{}
}

if len(names) >= limit {
Copy link
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
Collaborator

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":)

machine424 added a commit to machine424/prometheus that referenced this pull request May 17, 2024
Add warnings count check to TestEndpoints

The limit param was added in prometheus#13396

Signed-off-by: machine424 <ayoubmrini424@gmail.com>
machine424 added a commit to machine424/prometheus that referenced this pull request May 17, 2024
Add warnings count check to TestEndpoints

The limit param was added in prometheus#13396

Signed-off-by: machine424 <ayoubmrini424@gmail.com>
machine424 added a commit to machine424/prometheus that referenced this pull request May 17, 2024
for the the series, label names and label values APIs

Add warnings count check to TestEndpoints

The limit param was added in prometheus#13396

Signed-off-by: machine424 <ayoubmrini424@gmail.com>
machine424 added a commit that referenced this pull request May 21, 2024
for the the series, label names and label values APIs

Add warnings count check to TestEndpoints

The limit param was added in #13396

Signed-off-by: machine424 <ayoubmrini424@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants