How to properly paginate loki response

Hi there,

I’m trying, in some way, to expose the logs from loki endpoint to an external http.

My need, is somehow, to proxy the loki response through another API and query all the logs and returned them.

I’m using the API /loki/api/v1/query_range to fetch logs.

My understanding is that the pagination with loki, is somehow achieved by asking the next “page” that starts after the timestamp of latest row of the previous page.

So, if the query with limit 1000 returned the 999th and 1000th lines as follow:

2025-04-08 13:23:55,717 DEBUG [com.cloudiam...] 999
2025-04-08 13:23:55,788 DEBUG [com.cloudiam...] 1000

Then the next page should ask for the lines starting at 2025-04-08 13:23:55,789, one thousandth after the last row.

But in my case (and in a general manner), log generation can happen at the very same milliseconds:

2025-04-08 13:23:55,717 DEBUG [com.cloudiam...] 999
2025-04-08 13:23:55,788 DEBUG [com.cloudiam...] 1000
2025-04-08 13:23:55,788 DEBUG [com.cloudiam...] 1001
2025-04-08 13:23:55,810 DEBUG [com.cloudiam...] 1002

In that case, the line 1001 is skipped and will never be fetched.

This is even more visible with nginx access logs for instance that are timestamped with a precision of a second.

I’m sure there is a way to achieve that properly, maybe my assumption are wrong and pagination should be handled in a very different way.

Let me know :folded_hands:

Thanks in advance

M.

I am not an expert on this, so I could be wrong.

Because you can have multiple logs with the same timestamp (even down to nanosecond), it is possible that if you specify a batch size the batch could end in the middle of a second. There are two ways you can deal with this:

  1. LogCLI deal with this by aways using the start time with the end time of previous query, and keeping record of the previous query and remove the duplicates later, see loki/pkg/logcli/query/query.go at e297c51d201272b732b9115ce4c6f485621131cc · grafana/loki · GitHub. you will need nanosecond precision when doing queries.
  2. Another solution is to set the return limit dynamically. For example, let’s say your default interval is 5min and batch is 50000. You would first do a metrics query and find out the number of logs within 5min and see if it’s bigger than 50000, if not then proceed with query (which you’ll get all 50000 logs in one query). if yes then you divide the interval by half, and keep doing that until either the number of logs fix your batch size, or the interval is down to 1 second. if interval is down to 1 sec and it’s still bigger than 50000 then you’ll have to either increase the limit or go down to nanosecond precision for your interval.