From b60cbd5c545ae4bd67e8a5e1c5c30359db944529 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Wed, 22 May 2024 19:14:24 +0200 Subject: [PATCH] wip --- docs/VictoriaLogs/LogsQL.md | 12 ++++++++++++ lib/logstorage/filter_exact.go | 4 ++-- lib/logstorage/filter_exact_prefix.go | 2 +- lib/logstorage/parser.go | 24 ++++++++++++++++++++++-- lib/logstorage/parser_test.go | 17 +++++++++++------ lib/logstorage/pipe_extract_test.go | 4 ++-- 6 files changed, 50 insertions(+), 13 deletions(-) diff --git a/docs/VictoriaLogs/LogsQL.md b/docs/VictoriaLogs/LogsQL.md index 20791f36a..994170adf 100644 --- a/docs/VictoriaLogs/LogsQL.md +++ b/docs/VictoriaLogs/LogsQL.md @@ -573,6 +573,12 @@ For example, the following query matches the `error` value in the field `log:lev "log:level":exact("error") ``` +The `exact(...)` filter can be replaced with `=...` for convenience. For example, the following query is equivalent to the previous one: + +```logsql +"log:level":="error" +``` + See also: - [Exact prefix filter](#exact-prefix-filter) @@ -625,6 +631,12 @@ For example, the following query matches `log:level` values starting with `err` "log:level":exact("err"*) ``` +The `exact(...)` filter can be replaced with `=...` for convenience. For example, the following query is equivalent to the previous one: + +```logsql +"log:level":="err"* +``` + See also: - [Exact filter](#exact-filter) diff --git a/lib/logstorage/filter_exact.go b/lib/logstorage/filter_exact.go index fbd74d17d..98e9ea1ee 100644 --- a/lib/logstorage/filter_exact.go +++ b/lib/logstorage/filter_exact.go @@ -11,7 +11,7 @@ import ( // filterExact matches the exact value. // -// Example LogsQL: `fieldName:exact("foo bar")` +// Example LogsQL: `fieldName:exact("foo bar")` of `fieldName:="foo bar" type filterExact struct { fieldName string value string @@ -21,7 +21,7 @@ type filterExact struct { } func (fe *filterExact) String() string { - return fmt.Sprintf("%sexact(%s)", quoteFieldNameIfNeeded(fe.fieldName), quoteTokenIfNeeded(fe.value)) + return fmt.Sprintf("%s=%s", quoteFieldNameIfNeeded(fe.fieldName), quoteTokenIfNeeded(fe.value)) } func (fe *filterExact) updateNeededFields(neededFields fieldsSet) { diff --git a/lib/logstorage/filter_exact_prefix.go b/lib/logstorage/filter_exact_prefix.go index 653bdfc4b..e0b3b8648 100644 --- a/lib/logstorage/filter_exact_prefix.go +++ b/lib/logstorage/filter_exact_prefix.go @@ -20,7 +20,7 @@ type filterExactPrefix struct { } func (fep *filterExactPrefix) String() string { - return fmt.Sprintf("%sexact(%s*)", quoteFieldNameIfNeeded(fep.fieldName), quoteTokenIfNeeded(fep.prefix)) + return fmt.Sprintf("%s=%s*", quoteFieldNameIfNeeded(fep.fieldName), quoteTokenIfNeeded(fep.prefix)) } func (fep *filterExactPrefix) updateNeededFields(neededFields fieldsSet) { diff --git a/lib/logstorage/parser.go b/lib/logstorage/parser.go index 04f229cdd..04e9927e2 100644 --- a/lib/logstorage/parser.go +++ b/lib/logstorage/parser.go @@ -595,6 +595,8 @@ func parseGenericFilter(lex *lexer, fieldName string) (filter, error) { return parseFilterGT(lex, fieldName) case lex.isKeyword("<"): return parseFilterLT(lex, fieldName) + case lex.isKeyword("="): + return parseFilterEQ(lex, fieldName) case lex.isKeyword("not", "!"): return parseFilterNot(lex, fieldName) case lex.isKeyword("exact"): @@ -1015,6 +1017,24 @@ func parseFilterRegexp(lex *lexer, fieldName string) (filter, error) { }) } +func parseFilterEQ(lex *lexer, fieldName string) (filter, error) { + lex.nextToken() + phrase := getCompoundFuncArg(lex) + if lex.isKeyword("*") && !lex.isSkippedSpace { + lex.nextToken() + f := &filterExactPrefix{ + fieldName: fieldName, + prefix: phrase, + } + return f, nil + } + f := &filterExact{ + fieldName: fieldName, + value: phrase, + } + return f, nil +} + func parseFilterGT(lex *lexer, fieldName string) (filter, error) { lex.nextToken() @@ -1148,7 +1168,7 @@ func parseFilterRange(lex *lexer, fieldName string) (filter, error) { func parseFloat64(lex *lexer) (float64, string, error) { s, err := getCompoundToken(lex) if err != nil { - return 0, "", fmt.Errorf("cannot parse float64: %w", err) + return 0, "", fmt.Errorf("cannot parse float64 from %q: %w", s, err) } f, err := strconv.ParseFloat(s, 64) if err == nil { @@ -1161,7 +1181,7 @@ func parseFloat64(lex *lexer) (float64, string, error) { if err == nil { return float64(n), s, nil } - return 0, "", fmt.Errorf("cannot parse %q as float64: %w", lex.token, err) + return 0, "", fmt.Errorf("cannot parse %q as float64: %w", s, err) } func parseFuncArg(lex *lexer, fieldName string, callback func(args string) (filter, error)) (filter, error) { diff --git a/lib/logstorage/parser_test.go b/lib/logstorage/parser_test.go index 6f4eaf2a8..75e7f5f19 100644 --- a/lib/logstorage/parser_test.go +++ b/lib/logstorage/parser_test.go @@ -689,12 +689,17 @@ func TestParseQuerySuccess(t *testing.T) { f("string_range-a:x", `string_range-a:x`) // exact filter - f("exact(foo)", `exact(foo)`) - f("exact(foo*)", `exact(foo*)`) - f("exact('foo bar),|baz')", `exact("foo bar),|baz")`) - f("exact('foo bar),|baz'*)", `exact("foo bar),|baz"*)`) - f(`exact(foo/b:ar)`, `exact("foo/b:ar")`) - f(`foo:exact(foo/b:ar*)`, `foo:exact("foo/b:ar"*)`) + f("exact(foo)", `=foo`) + f("exact(foo*)", `=foo*`) + f("exact('foo bar),|baz')", `="foo bar),|baz"`) + f("exact('foo bar),|baz'*)", `="foo bar),|baz"*`) + f(`exact(foo/b:ar)`, `="foo/b:ar"`) + f(`foo:exact(foo/b:ar*)`, `foo:="foo/b:ar"*`) + f(`exact("foo/bar")`, `="foo/bar"`) + f(`exact('foo/bar')`, `="foo/bar"`) + f(`="foo/bar"`, `="foo/bar"`) + f("=foo=bar =b<=a>z ='abc'*", `="foo=bar" ="b<=a>z" =abc*`) + f("==foo =>=bar x : ( = =a=20)", `="=foo" =">=bar" x:="=a=20`) // i filter f("i(foo)", `i(foo)`) diff --git a/lib/logstorage/pipe_extract_test.go b/lib/logstorage/pipe_extract_test.go index 559ce4027..7a2d39f99 100644 --- a/lib/logstorage/pipe_extract_test.go +++ b/lib/logstorage/pipe_extract_test.go @@ -114,7 +114,7 @@ func TestPipeExtract(t *testing.T) { }) // single row, if match - f(`extract if (x:baz) "foo= baz=" from x`, [][]Field{ + f(`extract if (x:baz) "foo= baz=" from "x"`, [][]Field{ { {"x", `a foo=cc baz=aa b`}, {"bar", "abc"}, @@ -128,7 +128,7 @@ func TestPipeExtract(t *testing.T) { }) // single row, if mismatch - f(`extract if (bar:"") "foo= baz=" from x`, [][]Field{ + f(`extract if (bar:"") "foo= baz=" from 'x'`, [][]Field{ { {"x", `a foo=cc baz=aa b`}, {"bar", "abc"},