mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-31 15:06:26 +00:00
wip
This commit is contained in:
parent
1e2f5e7294
commit
b60cbd5c54
6 changed files with 50 additions and 13 deletions
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<b*='c*' >=20)", `="=foo" =">=bar" x:="=a<b"* x:="c*" x:>=20`)
|
||||
|
||||
// i filter
|
||||
f("i(foo)", `i(foo)`)
|
||||
|
|
|
@ -114,7 +114,7 @@ func TestPipeExtract(t *testing.T) {
|
|||
})
|
||||
|
||||
// single row, if match
|
||||
f(`extract if (x:baz) "foo=<bar> baz=<xx>" from x`, [][]Field{
|
||||
f(`extract if (x:baz) "foo=<bar> baz=<xx>" 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=<bar> baz=<xx>" from x`, [][]Field{
|
||||
f(`extract if (bar:"") "foo=<bar> baz=<xx>" from 'x'`, [][]Field{
|
||||
{
|
||||
{"x", `a foo=cc baz=aa b`},
|
||||
{"bar", "abc"},
|
||||
|
|
Loading…
Reference in a new issue