mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
lib/logstorage: allow special chars in unquoted _stream tag names and values
This simplifies writing _stream filters. For example, {foo-bar=abc:de} can be written instead of {"foo-bar"="abc:de"}
This commit is contained in:
parent
462b7cd597
commit
89686094a0
3 changed files with 29 additions and 11 deletions
|
@ -919,6 +919,10 @@ func getCompoundSuffix(lex *lexer, allowColon bool) string {
|
||||||
|
|
||||||
func getCompoundToken(lex *lexer) (string, error) {
|
func getCompoundToken(lex *lexer) (string, error) {
|
||||||
stopTokens := []string{",", "(", ")", "[", "]", "|", ""}
|
stopTokens := []string{",", "(", ")", "[", "]", "|", ""}
|
||||||
|
return getCompoundTokenExt(lex, stopTokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCompoundTokenExt(lex *lexer, stopTokens []string) (string, error) {
|
||||||
if lex.isKeyword(stopTokens...) {
|
if lex.isKeyword(stopTokens...) {
|
||||||
return "", fmt.Errorf("compound token cannot start with '%s'", lex.token)
|
return "", fmt.Errorf("compound token cannot start with '%s'", lex.token)
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,8 @@ func (af *andStreamFilter) String() string {
|
||||||
type streamTagFilter struct {
|
type streamTagFilter struct {
|
||||||
// tagName is the name for the tag to filter
|
// tagName is the name for the tag to filter
|
||||||
tagName string
|
tagName string
|
||||||
// op is operation such as `=`, `!=`, `=~` or `!~`
|
|
||||||
|
// op is operation such as `=`, `!=`, `=~`, `!~` or `:`
|
||||||
op string
|
op string
|
||||||
|
|
||||||
// value is the value
|
// value is the value
|
||||||
|
@ -164,20 +165,23 @@ func parseAndStreamFilter(lex *lexer) (*andStreamFilter, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseStreamTagFilter(lex *lexer) (*streamTagFilter, error) {
|
func parseStreamTagFilter(lex *lexer) (*streamTagFilter, error) {
|
||||||
tagName := lex.token
|
// parse tagName
|
||||||
if !lex.mustNextToken() {
|
tagName, err := parseStreamTagName(lex)
|
||||||
return nil, fmt.Errorf("missing operation in _stream filter for %q field", tagName)
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot parse stream tag name: %w", err)
|
||||||
}
|
}
|
||||||
if !lex.isKeyword("=", "!=", "=~", "!~") {
|
if !lex.isKeyword("=", "!=", "=~", "!~") {
|
||||||
return nil, fmt.Errorf("unsupported operation %q in _steam filter for %q field; supported operations: =, !=, =~, !~", lex.token, tagName)
|
return nil, fmt.Errorf("unsupported operation %q in _steam filter for %q field; supported operations: =, !=, =~, !~", lex.token, tagName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parse op
|
||||||
op := lex.token
|
op := lex.token
|
||||||
if !lex.mustNextToken() {
|
lex.nextToken()
|
||||||
return nil, fmt.Errorf("missing _stream filter value for %q field", tagName)
|
|
||||||
}
|
// parse tag value
|
||||||
value := lex.token
|
value, err := parseStreamTagValue(lex)
|
||||||
if !lex.mustNextToken() {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("missing token after %q%s%q filter", tagName, op, value)
|
return nil, fmt.Errorf("cannot parse value for tag %q: %w", tagName, err)
|
||||||
}
|
}
|
||||||
stf := &streamTagFilter{
|
stf := &streamTagFilter{
|
||||||
tagName: tagName,
|
tagName: tagName,
|
||||||
|
@ -194,6 +198,16 @@ func parseStreamTagFilter(lex *lexer) (*streamTagFilter, error) {
|
||||||
return stf, nil
|
return stf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseStreamTagName(lex *lexer) (string, error) {
|
||||||
|
stopTokens := []string{"=", "!=", "=~", "!~", ",", "{", "}", "'", `"`, "`", ""}
|
||||||
|
return getCompoundTokenExt(lex, stopTokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseStreamTagValue(lex *lexer) (string, error) {
|
||||||
|
stopTokens := []string{",", "{", "}", "'", `"`, "`", ""}
|
||||||
|
return getCompoundTokenExt(lex, stopTokens)
|
||||||
|
}
|
||||||
|
|
||||||
func getStreamName() *streamName {
|
func getStreamName() *streamName {
|
||||||
v := streamNamePool.Get()
|
v := streamNamePool.Get()
|
||||||
if v == nil {
|
if v == nil {
|
||||||
|
|
|
@ -163,7 +163,7 @@ func TestNewTestStreamFilterSuccess(t *testing.T) {
|
||||||
f(`{foo="bar"}`, `{foo="bar"}`)
|
f(`{foo="bar"}`, `{foo="bar"}`)
|
||||||
f(`{ "foo" =~ "bar.+" , baz!="a" or x="y"}`, `{foo=~"bar.+",baz!="a" or x="y"}`)
|
f(`{ "foo" =~ "bar.+" , baz!="a" or x="y"}`, `{foo=~"bar.+",baz!="a" or x="y"}`)
|
||||||
f(`{"a b"='c}"d' OR de="aaa"}`, `{"a b"="c}\"d" or de="aaa"}`)
|
f(`{"a b"='c}"d' OR de="aaa"}`, `{"a b"="c}\"d" or de="aaa"}`)
|
||||||
f(`{a="b", c="d" or x="y"}`, `{a="b",c="d" or x="y"}`)
|
f(`{a-q:w.z="b", c="d" or 'x a'=y-z=q}`, `{"a-q:w.z"="b",c="d" or "x a"="y-z=q"}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewTestStreamFilterFailure(t *testing.T) {
|
func TestNewTestStreamFilterFailure(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue