GET /api/v1/logs?query=<LogsQL filter>&since=<cursor|RFC 3339|15m/6h/7d>&limit=<1..10000, default 1000>&lag=<default 30s> returns {rows, next_cursor, has_more, until, waiting?}, rows sorted by _time (reception time).
Stable cursor: position on _time plus the number of rows already returned among those with that exact _time, ordered by a hash of their content. A page never cuts a group in an unstable way, so following the cursors gives every row once (identical rows included).
Rows only count once older than lag (queue, reverse DNS), and nothing is returned (waiting: true, same cursor) while the disk spool still holds logs, so late-stored logs are not skipped.
API tokens (Settings > API, admins only): create (shown once), last use and IP, revoke. Stored as SHA-256 in /data/api_tokens.json (0600). Authorization: Bearer lst_…, read-only, /api/v1/ only, valid in local, OIDC and no-auth modes.
go vet, go build, go test -race -count=3 ./... OK. Cursor tests against a fake VictoriaLogs that shuffles rows sharing a timestamp: no loss or duplicate for limits 1 to 1000 with groups larger than a page, and new logs arriving between polls. Token tests: storage, hash only, revocation, Bearer scope, local auth bypass. UI checked in a static preview.
Not tested against a real VictoriaLogs: the _time:[T, T] exact-time query should be checked in the lab.
<!-- claude-projects-attribution: {"github_login":"vblogio"} -->
_Requested by **Cédric**_
## What
- `GET /api/v1/logs?query=<LogsQL filter>&since=<cursor|RFC 3339|15m/6h/7d>&limit=<1..10000, default 1000>&lag=<default 30s>` returns `{rows, next_cursor, has_more, until, waiting?}`, rows sorted by `_time` (reception time).
- Stable cursor: position on `_time` plus the number of rows already returned among those with that exact `_time`, ordered by a hash of their content. A page never cuts a group in an unstable way, so following the cursors gives every row once (identical rows included).
- Rows only count once older than `lag` (queue, reverse DNS), and nothing is returned (`waiting: true`, same cursor) while the disk spool still holds logs, so late-stored logs are not skipped.
- API tokens (Settings > API, admins only): create (shown once), last use and IP, revoke. Stored as SHA-256 in `/data/api_tokens.json` (0600). `Authorization: Bearer lst_…`, read-only, `/api/v1/` only, valid in local, OIDC and no-auth modes.
- README EN/FR: route, parameters, errors, n8n workflow (Schedule Trigger, Code + `$getWorkflowStaticData`, HTTP Request, Code).
## Tests
`go vet`, `go build`, `go test -race -count=3 ./...` OK. Cursor tests against a fake VictoriaLogs that shuffles rows sharing a timestamp: no loss or duplicate for limits 1 to 1000 with groups larger than a page, and new logs arriving between polls. Token tests: storage, hash only, revocation, Bearer scope, local auth bypass. UI checked in a static preview.
Not tested against a real VictoriaLogs: the `_time:[T, T]` exact-time query should be checked in the lab.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
GET /api/v1/logs?query=<LogsQL>&since=<cursor|time|duration>&limit=<n>
returns the logs after a cursor, oldest first, with next_cursor and
has_more. The cursor is a position on _time (the reception time) plus
the number of rows already returned among those sharing that exact
time, ordered by a hash of their content, so following the cursors
gives every row once even within groups cut by a page. Rows count once
older than the lag (30 s), and nothing is returned while the disk
spool still holds logs.
API tokens (Settings > API) give read-only access to /api/v1/ as
"Authorization: Bearer lst_...", in every auth mode; only their SHA-256
is kept in /data/api_tokens.json. README (EN/FR) documents the route and
an n8n workflow keeping the cursor in $getWorkflowStaticData.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
claudeBot
marked the pull request as ready for review 2026-11-01 15:52:39 +01:00
claudeBot
merged commit e77fcb326d into main2026-11-01 15:52:42 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Requested by Cédric
What
GET /api/v1/logs?query=<LogsQL filter>&since=<cursor|RFC 3339|15m/6h/7d>&limit=<1..10000, default 1000>&lag=<default 30s>returns{rows, next_cursor, has_more, until, waiting?}, rows sorted by_time(reception time)._timeplus the number of rows already returned among those with that exact_time, ordered by a hash of their content. A page never cuts a group in an unstable way, so following the cursors gives every row once (identical rows included).lag(queue, reverse DNS), and nothing is returned (waiting: true, same cursor) while the disk spool still holds logs, so late-stored logs are not skipped./data/api_tokens.json(0600).Authorization: Bearer lst_…, read-only,/api/v1/only, valid in local, OIDC and no-auth modes.$getWorkflowStaticData, HTTP Request, Code).Tests
go vet,go build,go test -race -count=3 ./...OK. Cursor tests against a fake VictoriaLogs that shuffles rows sharing a timestamp: no loss or duplicate for limits 1 to 1000 with groups larger than a page, and new logs arriving between polls. Token tests: storage, hash only, revocation, Bearer scope, local auth bypass. UI checked in a static preview.Not tested against a real VictoriaLogs: the
_time:[T, T]exact-time query should be checked in the lab.🤖 Generated with Claude Code