feat: Support negative numbers in LogQL (#13091)

pull/13161/head
benclive 12 months ago committed by GitHub
parent fa2c78936f
commit 6df81db978
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 23
      pkg/logql/syntax/ast_test.go
  2. 14
      pkg/logql/syntax/expr.y
  3. 535
      pkg/logql/syntax/expr.y.go
  4. 14
      pkg/logql/syntax/lex_test.go
  5. 8
      pkg/logql/syntax/parser_test.go

@ -49,6 +49,7 @@ func Test_logSelectorExpr_String(t *testing.T) {
{`{foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap" | logfmt | b=ip("127.0.0.1") | level="error" | c=ip("::1")`, true}, // chain inside label filters.
{`{foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap" | regexp "(?P<foo>foo|bar)"`, true},
{`{foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap" | regexp "(?P<foo>foo|bar)" | ( ( foo<5.01 , bar>20ms ) or foo="bar" ) | line_format "blip{{.boop}}bap" | label_format foo=bar,bar="blip{{.blop}}"`, true},
{`{foo="bar"} | logfmt | counter>-1 | counter>=-1 | counter<-1 | counter<=-1 | counter!=-1 | counter==-1`, true},
}
for _, tt := range tests {
@ -76,6 +77,7 @@ func Test_logSelectorExpr_String(t *testing.T) {
func Test_SampleExpr_String(t *testing.T) {
t.Parallel()
for _, tc := range []string{
`rate( ( {job="mysql"} |="error" !="timeout" ) [10s] )>-1`,
`rate( ( {job="mysql"} |="error" !="timeout" ) [10s] )`,
`absent_over_time( ( {job="mysql"} |="error" !="timeout" ) [10s] )`,
`absent_over_time( ( {job="mysql"} |="error" !="timeout" ) [10s] offset 10d )`,
@ -556,6 +558,27 @@ func Test_FilterMatcher(t *testing.T) {
},
[]linecheck{{"foo", false}, {"bar", false}, {"none", true}},
},
{
`{app="foo"} | logfmt | duration > -1s`,
[]*labels.Matcher{
mustNewMatcher(labels.MatchEqual, "app", "foo"),
},
[]linecheck{{"duration=5m", true}, {"duration=1s", true}, {"duration=0s", true}, {"duration=-5m", false}},
},
{
`{app="foo"} | logfmt | count > -1`,
[]*labels.Matcher{
mustNewMatcher(labels.MatchEqual, "app", "foo"),
},
[]linecheck{{"count=5", true}, {"count=1", true}, {"count=0", true}, {"count=-5", false}},
},
{
`{app="foo"} | logfmt | counter <= -1`,
[]*labels.Matcher{
mustNewMatcher(labels.MatchEqual, "app", "foo"),
},
[]linecheck{{"counter=1", false}, {"counter=0", false}, {"counter=-1", true}, {"counter=-2", true}},
},
} {
tt := tt
t.Run(tt.q, func(t *testing.T) {

@ -400,13 +400,13 @@ bytesFilter:
;
numberFilter:
IDENTIFIER GT NUMBER { $$ = log.NewNumericLabelFilter(log.LabelFilterGreaterThan, $1, mustNewFloat($3))}
| IDENTIFIER GTE NUMBER { $$ = log.NewNumericLabelFilter(log.LabelFilterGreaterThanOrEqual, $1, mustNewFloat($3))}
| IDENTIFIER LT NUMBER { $$ = log.NewNumericLabelFilter(log.LabelFilterLesserThan, $1, mustNewFloat($3))}
| IDENTIFIER LTE NUMBER { $$ = log.NewNumericLabelFilter(log.LabelFilterLesserThanOrEqual, $1, mustNewFloat($3))}
| IDENTIFIER NEQ NUMBER { $$ = log.NewNumericLabelFilter(log.LabelFilterNotEqual, $1, mustNewFloat($3))}
| IDENTIFIER EQ NUMBER { $$ = log.NewNumericLabelFilter(log.LabelFilterEqual, $1, mustNewFloat($3))}
| IDENTIFIER CMP_EQ NUMBER { $$ = log.NewNumericLabelFilter(log.LabelFilterEqual, $1, mustNewFloat($3))}
IDENTIFIER GT literalExpr { $$ = log.NewNumericLabelFilter(log.LabelFilterGreaterThan, $1, $3.Val)}
| IDENTIFIER GTE literalExpr { $$ = log.NewNumericLabelFilter(log.LabelFilterGreaterThanOrEqual, $1,$3.Val)}
| IDENTIFIER LT literalExpr { $$ = log.NewNumericLabelFilter(log.LabelFilterLesserThan, $1, $3.Val)}
| IDENTIFIER LTE literalExpr { $$ = log.NewNumericLabelFilter(log.LabelFilterLesserThanOrEqual, $1, $3.Val)}
| IDENTIFIER NEQ literalExpr { $$ = log.NewNumericLabelFilter(log.LabelFilterNotEqual, $1, $3.Val)}
| IDENTIFIER EQ literalExpr { $$ = log.NewNumericLabelFilter(log.LabelFilterEqual, $1, $3.Val)}
| IDENTIFIER CMP_EQ literalExpr { $$ = log.NewNumericLabelFilter(log.LabelFilterEqual, $1, $3.Val)}
;
dropLabel:

File diff suppressed because it is too large Load Diff

@ -95,6 +95,19 @@ func TestLex(t *testing.T) {
{`{foo="bar"} | logfmt --strict code"`, []int{OPEN_BRACE, IDENTIFIER, EQ, STRING, CLOSE_BRACE, PIPE, LOGFMT, PARSER_FLAG, IDENTIFIER}},
{`{foo="bar"} | logfmt --keep-empty --strict code="response.code", IPAddress="host"`, []int{OPEN_BRACE, IDENTIFIER, EQ, STRING, CLOSE_BRACE, PIPE, LOGFMT, PARSER_FLAG, PARSER_FLAG, IDENTIFIER, EQ, STRING, COMMA, IDENTIFIER, EQ, STRING}},
{`decolorize`, []int{DECOLORIZE}},
{`123`, []int{NUMBER}},
{`-123`, []int{SUB, NUMBER}},
{`123.45`, []int{NUMBER}},
{`-123.45`, []int{SUB, NUMBER}},
{`123KB`, []int{BYTES}},
// Skip -123KB: Negative bytes are explicitly not supported in the Lexer.
{`123ms`, []int{DURATION}},
{`-123ms`, []int{DURATION}},
{`34 + - 123`, []int{NUMBER, ADD, SUB, NUMBER}},
{`34 + -123`, []int{NUMBER, ADD, SUB, NUMBER}},
{`34+-123`, []int{NUMBER, ADD, SUB, NUMBER}},
{`34-123`, []int{NUMBER, SUB, NUMBER}},
{`sum(rate({foo="bar"}[5m])-1 > 30`, []int{SUM, OPEN_PARENTHESIS, RATE, OPEN_PARENTHESIS, OPEN_BRACE, IDENTIFIER, EQ, STRING, CLOSE_BRACE, RANGE, CLOSE_PARENTHESIS, SUB, NUMBER, GT, NUMBER}},
} {
t.Run(tc.input, func(t *testing.T) {
actual := []int{}
@ -179,6 +192,7 @@ func Test_parseDuration(t *testing.T) {
{"1w", WEEK},
{"1d", DAY},
{"1h15m30.918273645s", time.Hour + 15*time.Minute + 30*time.Second + 918273645*time.Nanosecond},
{"-1s", -1 * time.Second},
} {
actual, err := parseDuration(tc.input)

@ -499,19 +499,19 @@ var ParseTestCases = []struct {
// label filter for ip-matcher
{
in: `{ foo = "bar" }|logfmt|addr>=ip("1.2.3.4")`,
err: logqlmodel.NewParseError("syntax error: unexpected ip, expecting BYTES or NUMBER or DURATION", 1, 30),
err: logqlmodel.NewParseError("syntax error: unexpected ip", 1, 30),
},
{
in: `{ foo = "bar" }|logfmt|addr>ip("1.2.3.4")`,
err: logqlmodel.NewParseError("syntax error: unexpected ip, expecting BYTES or NUMBER or DURATION", 1, 29),
err: logqlmodel.NewParseError("syntax error: unexpected ip", 1, 29),
},
{
in: `{ foo = "bar" }|logfmt|addr<=ip("1.2.3.4")`,
err: logqlmodel.NewParseError("syntax error: unexpected ip, expecting BYTES or NUMBER or DURATION", 1, 30),
err: logqlmodel.NewParseError("syntax error: unexpected ip", 1, 30),
},
{
in: `{ foo = "bar" }|logfmt|addr<ip("1.2.3.4")`,
err: logqlmodel.NewParseError("syntax error: unexpected ip, expecting BYTES or NUMBER or DURATION", 1, 29),
err: logqlmodel.NewParseError("syntax error: unexpected ip", 1, 29),
},
{
in: `{ foo = "bar" }|logfmt|addr=ip("1.2.3.4")`,

Loading…
Cancel
Save