From 401e79e0d878799c73a62d61d13538e89b91f762 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Mon, 27 May 2024 14:22:18 +0200 Subject: [PATCH] wip --- docs/VictoriaLogs/CHANGELOG.md | 2 ++ docs/VictoriaLogs/LogsQL.md | 6 ++++++ lib/logstorage/parser_test.go | 10 ++++------ lib/logstorage/pipe_limit.go | 17 +++++++++++------ lib/logstorage/pipe_limit_test.go | 12 +++++++++++- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/docs/VictoriaLogs/CHANGELOG.md b/docs/VictoriaLogs/CHANGELOG.md index b569f6195..eec03ea26 100644 --- a/docs/VictoriaLogs/CHANGELOG.md +++ b/docs/VictoriaLogs/CHANGELOG.md @@ -19,6 +19,8 @@ according to [these docs](https://docs.victoriametrics.com/victorialogs/quicksta ## tip +* FEATURE: allow [`head` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#limit-pipe) without number. For example, `error | head`. In this case 10 last values are returned as `head` Unix command does by default. + ## [v0.12.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v0.12.1-victorialogs) Released at 2024-05-26 diff --git a/docs/VictoriaLogs/LogsQL.md b/docs/VictoriaLogs/LogsQL.md index 8b6e17467..b1455e9e0 100644 --- a/docs/VictoriaLogs/LogsQL.md +++ b/docs/VictoriaLogs/LogsQL.md @@ -1463,6 +1463,12 @@ _time:5m | limit 100 `head` keyword can be used instead of `limit` for convenience. For example, `_time:5m | head 100` is equivalent to `_time:5m | limit 100`. +The `N` in `head N` can be omitted - in this case up to 10 matching logs are returned: + +```logsql +error | head +``` + By default rows are selected in arbitrary order because of performance reasons, so the query above can return different sets of logs every time it is executed. [`sort` pipe](#sort-pipe) can be used for making sure the logs are in the same order before applying `limit ...` to them. diff --git a/lib/logstorage/parser_test.go b/lib/logstorage/parser_test.go index 4b80b66b8..4ba801927 100644 --- a/lib/logstorage/parser_test.go +++ b/lib/logstorage/parser_test.go @@ -869,8 +869,10 @@ func TestParseQuerySuccess(t *testing.T) { f(`* | DELETE foo, bar`, `* | delete foo, bar`) // limit and head pipe - f(`foo | limit 10`, `foo | limit 10`) - f(`foo | head 10`, `foo | limit 10`) + f(`foo | limit`, `foo | limit 10`) + f(`foo | head`, `foo | limit 10`) + f(`foo | limit 20`, `foo | limit 20`) + f(`foo | head 20`, `foo | limit 20`) f(`foo | HEAD 1_123_432`, `foo | limit 1123432`) f(`foo | head 10K`, `foo | limit 10000`) @@ -1313,10 +1315,6 @@ func TestParseQueryFailure(t *testing.T) { f(`foo | delete foo,`) f(`foo | delete foo,,`) - // missing limit and head pipe value - f(`foo | limit`) - f(`foo | head`) - // invalid limit pipe value f(`foo | limit bar`) f(`foo | limit -123`) diff --git a/lib/logstorage/pipe_limit.go b/lib/logstorage/pipe_limit.go index 2f4054393..964307cfc 100644 --- a/lib/logstorage/pipe_limit.go +++ b/lib/logstorage/pipe_limit.go @@ -88,15 +88,20 @@ func parsePipeLimit(lex *lexer) (*pipeLimit, error) { if !lex.isKeyword("limit", "head") { return nil, fmt.Errorf("expecting 'limit' or 'head'; got %q", lex.token) } + lex.nextToken() - lex.nextToken() - n, err := parseUint(lex.token) - if err != nil { - return nil, fmt.Errorf("cannot parse rows limit from %q: %w", lex.token, err) + limit := uint64(10) + if !lex.isKeyword("|", ")", "") { + n, err := parseUint(lex.token) + if err != nil { + return nil, fmt.Errorf("cannot parse rows limit from %q: %w", lex.token, err) + } + lex.nextToken() + limit = n } - lex.nextToken() + pl := &pipeLimit{ - limit: n, + limit: limit, } return pl, nil } diff --git a/lib/logstorage/pipe_limit_test.go b/lib/logstorage/pipe_limit_test.go index bc7afa4fd..23b176ee1 100644 --- a/lib/logstorage/pipe_limit_test.go +++ b/lib/logstorage/pipe_limit_test.go @@ -20,7 +20,6 @@ func TestParsePipeLimitFailure(t *testing.T) { expectParsePipeFailure(t, pipeStr) } - f(`limit`) f(`limit -10`) f(`limit foo`) } @@ -30,6 +29,17 @@ func TestPipeLimit(t *testing.T) { t.Helper() expectPipeResults(t, pipeStr, rows, rowsExpected) } + f("limit", [][]Field{ + { + {"_msg", `{"foo":"bar"}`}, + {"a", `test`}, + }, + }, [][]Field{ + { + {"_msg", `{"foo":"bar"}`}, + {"a", `test`}, + }, + }) f("limit 100", [][]Field{ {