From 0c77cb1f884c4dc2880861f1d8b26cfff62ddca5 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Sun, 19 May 2024 19:16:28 +0200 Subject: [PATCH] wip --- app/vlselect/logsql/logsql.go | 5 ++++- docs/VictoriaLogs/querying/README.md | 17 +++++++++++++++-- lib/logstorage/parser.go | 20 ++++++++++++++------ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/app/vlselect/logsql/logsql.go b/app/vlselect/logsql/logsql.go index 23b53ab1d..73401d0e2 100644 --- a/app/vlselect/logsql/logsql.go +++ b/app/vlselect/logsql/logsql.go @@ -52,7 +52,10 @@ func ProcessHitsRequest(ctx context.Context, w http.ResponseWriter, r *http.Requ return } - q.AddCountByTimePipe(int64(step), int64(offset)) + // Obtain field entries + fields := r.Form["field"] + + q.AddCountByTimePipe(int64(step), int64(offset), fields) q.Optimize() var wLock sync.Mutex diff --git a/docs/VictoriaLogs/querying/README.md b/docs/VictoriaLogs/querying/README.md index 9049db6d3..fec657b6f 100644 --- a/docs/VictoriaLogs/querying/README.md +++ b/docs/VictoriaLogs/querying/README.md @@ -102,10 +102,10 @@ The `` arg can contain values in [the format specified here](https://docs. If `` is missing, then it equals to `1d` (one day). For example, the following command returns per-hour number of [log messages](https://docs.victoriametrics.com/victorialogs/keyconcepts/#message-field) -with the `error` [word](https://docs.victoriametrics.com/victorialogs/logsql/#word) over logs for the 3 hour day: +with the `error` [word](https://docs.victoriametrics.com/victorialogs/logsql/#word) over logs for the 3 hours: ```sh -curl http://localhost:9428/select/logsql/hits -d 'query=error' -d 'start=1d' -d 'step=1h' +curl http://localhost:9428/select/logsql/hits -d 'query=error' -d 'start=3h' -d 'step=1h' ``` Below is an example JSON output returned from this endpoint: @@ -130,6 +130,19 @@ Below is an example JSON output returned from this endpoint: Additionally, the `offset=` arg can be passed to `/select/logsql/hits` in order to group buckets according to the given timezone offset. The `` can contain values in [the format specified here](https://docs.victoriametrics.com/victorialogs/logsql/#duration-values). +For example, the following command returns per-day number of logs with `error` [word](https://docs.victoriametrics.com/victorialogs/logsql/#word) +over the last week in New York time zone (`-4h`): + +```logsql +curl http://localhost:9428/select/logsql/hits -d 'query=error' -d 'start=1w' -d 'step=1d' -d 'offset=-4h' +``` + +Additionally, any number of `field=` args can be passed to `/select/logsql/hits` for grouping hits buckets by the mentioned `` fields. +For example, the following query groups hits by `level` [field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model) additionally to the provided `step`: + +```logsql +curl http://localhost:9428/select/logsql/hits -d 'query=*' -d 'start=1w' -d 'step=1d' -d 'field=level' +``` See also: diff --git a/lib/logstorage/parser.go b/lib/logstorage/parser.go index dc7420ce6..ef0ce27db 100644 --- a/lib/logstorage/parser.go +++ b/lib/logstorage/parser.go @@ -220,13 +220,17 @@ func (q *Query) String() string { return s } -// AddCountByTimePipe adds '| stats by (_time:step offset off) count() hits' to the end of q. -func (q *Query) AddCountByTimePipe(step, off int64) { +// AddCountByTimePipe adds '| stats by (_time:step offset off, field1, ..., fieldN) count() hits' to the end of q. +func (q *Query) AddCountByTimePipe(step, off int64, fields []string) { { - // add 'stats by (_time:step offset off) count() hits' + // add 'stats by (_time:step offset off, fields) count() hits' stepStr := string(marshalDuration(nil, step)) offsetStr := string(marshalDuration(nil, off)) - s := fmt.Sprintf("stats by (_time:%s offset %s) count() hits", stepStr, offsetStr) + byFieldsStr := "_time:" + stepStr + " offset " + offsetStr + for _, f := range fields { + byFieldsStr += ", " + quoteTokenIfNeeded(f) + } + s := fmt.Sprintf("stats by (%s) count() hits", byFieldsStr) lex := newLexer(s) ps, err := parsePipeStats(lex) if err != nil { @@ -236,8 +240,12 @@ func (q *Query) AddCountByTimePipe(step, off int64) { } { - // Add 'sort by (_time)' in order to get consistent order of the results. - s := "sort by (_time)" + // Add 'sort by (_time, fields)' in order to get consistent order of the results. + sortFieldsStr := "_time" + for _, f := range fields { + sortFieldsStr += ", " + quoteTokenIfNeeded(f) + } + s := fmt.Sprintf("sort by (%s)", sortFieldsStr) lex := newLexer(s) ps, err := parsePipeSort(lex) if err != nil {