github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logql/syntax/parser_test.go (about) 1 package syntax 2 3 import ( 4 "errors" 5 "reflect" 6 "testing" 7 "time" 8 9 "github.com/prometheus/prometheus/model/labels" 10 "github.com/stretchr/testify/require" 11 12 "github.com/grafana/loki/pkg/logql/log" 13 "github.com/grafana/loki/pkg/logqlmodel" 14 ) 15 16 func NewStringLabelFilter(s string) *string { 17 return &s 18 } 19 20 func TestParse(t *testing.T) { 21 for _, tc := range []struct { 22 in string 23 exp Expr 24 err error 25 }{ 26 { 27 // raw string 28 in: "count_over_time({foo=~`bar\\w+`}[12h] |~ `error\\`)", 29 exp: &RangeAggregationExpr{ 30 Operation: "count_over_time", 31 Left: &LogRange{ 32 Left: &PipelineExpr{ 33 MultiStages: MultiStageExpr{ 34 newLineFilterExpr(labels.MatchRegexp, "", "error\\"), 35 }, 36 Left: &MatchersExpr{ 37 Mts: []*labels.Matcher{ 38 mustNewMatcher(labels.MatchRegexp, "foo", "bar\\w+"), 39 }, 40 }, 41 }, 42 Interval: 12 * time.Hour, 43 }, 44 }, 45 }, 46 { 47 // test [12h] before filter expr 48 in: `count_over_time({foo="bar"}[12h] |= "error")`, 49 exp: &RangeAggregationExpr{ 50 Operation: "count_over_time", 51 Left: &LogRange{ 52 Left: newPipelineExpr( 53 newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "foo", Value: "bar"}}), 54 MultiStageExpr{ 55 newLineFilterExpr(labels.MatchEqual, "", "error"), 56 }, 57 ), 58 Interval: 12 * time.Hour, 59 }, 60 }, 61 }, 62 { 63 // test [12h] after filter expr 64 in: `count_over_time({foo="bar"} |= "error" [12h])`, 65 exp: &RangeAggregationExpr{ 66 Operation: "count_over_time", 67 Left: &LogRange{ 68 Left: newPipelineExpr( 69 newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "foo", Value: "bar"}}), 70 MultiStageExpr{newLineFilterExpr(labels.MatchEqual, "", "error")}, 71 ), 72 Interval: 12 * time.Hour, 73 }, 74 }, 75 }, 76 { 77 in: `{foo="bar"}`, 78 exp: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 79 }, 80 { 81 in: `{ foo = "bar" }`, 82 exp: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 83 }, 84 { 85 in: `{ namespace="buzz", foo != "bar" }`, 86 exp: &MatchersExpr{Mts: []*labels.Matcher{ 87 mustNewMatcher(labels.MatchEqual, "namespace", "buzz"), 88 mustNewMatcher(labels.MatchNotEqual, "foo", "bar"), 89 }}, 90 }, 91 { 92 in: `{ foo =~ "bar" }`, 93 exp: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchRegexp, "foo", "bar")}}, 94 }, 95 { 96 in: `{ namespace="buzz", foo !~ "bar" }`, 97 exp: &MatchersExpr{Mts: []*labels.Matcher{ 98 mustNewMatcher(labels.MatchEqual, "namespace", "buzz"), 99 mustNewMatcher(labels.MatchNotRegexp, "foo", "bar"), 100 }}, 101 }, 102 { 103 in: `count_over_time({ foo = "bar" }[12m])`, 104 exp: &RangeAggregationExpr{ 105 Left: &LogRange{ 106 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 107 Interval: 12 * time.Minute, 108 }, 109 Operation: "count_over_time", 110 }, 111 }, 112 { 113 in: `bytes_over_time({ foo = "bar" }[12m])`, 114 exp: &RangeAggregationExpr{ 115 Left: &LogRange{ 116 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 117 Interval: 12 * time.Minute, 118 }, 119 Operation: OpRangeTypeBytes, 120 }, 121 }, 122 { 123 in: `bytes_rate({ foo = "bar" }[12m])`, 124 exp: &RangeAggregationExpr{ 125 Left: &LogRange{ 126 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 127 Interval: 12 * time.Minute, 128 }, 129 Operation: OpRangeTypeBytesRate, 130 }, 131 }, 132 { 133 in: `rate({ foo = "bar" }[5h])`, 134 exp: &RangeAggregationExpr{ 135 Left: &LogRange{ 136 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 137 Interval: 5 * time.Hour, 138 }, 139 Operation: "rate", 140 }, 141 }, 142 { 143 in: `{ foo = "bar" }|logfmt|rate="a"`, // rate should also be able to use it as IDENTIFIER 144 exp: newPipelineExpr( 145 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 146 MultiStageExpr{ 147 newLabelParserExpr(OpParserTypeLogfmt, ""), 148 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "rate", "a"))), 149 }, 150 ), 151 }, 152 { 153 in: `{ foo = "bar" }|logfmt|length>5d`, 154 exp: newPipelineExpr( 155 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 156 MultiStageExpr{ 157 newLabelParserExpr(OpParserTypeLogfmt, ""), 158 newLabelFilterExpr(log.NewDurationLabelFilter(log.LabelFilterGreaterThan, "length", 5*24*time.Hour)), 159 }, 160 ), 161 }, 162 { 163 in: `rate({ foo = "bar" }[5d])`, 164 exp: &RangeAggregationExpr{ 165 Left: &LogRange{ 166 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 167 Interval: 5 * 24 * time.Hour, 168 }, 169 Operation: "rate", 170 }, 171 }, 172 { 173 in: `count_over_time({ foo = "bar" }[1w])`, 174 exp: &RangeAggregationExpr{ 175 Left: &LogRange{ 176 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 177 Interval: 7 * 24 * time.Hour, 178 }, 179 Operation: "count_over_time", 180 }, 181 }, 182 { 183 in: `absent_over_time({ foo = "bar" }[1w])`, 184 exp: &RangeAggregationExpr{ 185 Left: &LogRange{ 186 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 187 Interval: 7 * 24 * time.Hour, 188 }, 189 Operation: OpRangeTypeAbsent, 190 }, 191 }, 192 { 193 in: `sum(rate({ foo = "bar" }[5h]))`, 194 exp: mustNewVectorAggregationExpr(&RangeAggregationExpr{ 195 Left: &LogRange{ 196 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 197 Interval: 5 * time.Hour, 198 }, 199 Operation: "rate", 200 }, "sum", nil, nil), 201 }, 202 { 203 in: `sum(rate({ foo ="bar" }[1y]))`, 204 exp: mustNewVectorAggregationExpr(&RangeAggregationExpr{ 205 Left: &LogRange{ 206 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 207 Interval: 365 * 24 * time.Hour, 208 }, 209 Operation: "rate", 210 }, "sum", nil, nil), 211 }, 212 { 213 in: `avg(count_over_time({ foo = "bar" }[5h])) by (bar,foo)`, 214 exp: mustNewVectorAggregationExpr(&RangeAggregationExpr{ 215 Left: &LogRange{ 216 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 217 Interval: 5 * time.Hour, 218 }, 219 Operation: "count_over_time", 220 }, "avg", &Grouping{ 221 Without: false, 222 Groups: []string{"bar", "foo"}, 223 }, nil), 224 }, 225 { 226 in: `avg( 227 label_replace( 228 count_over_time({ foo = "bar" }[5h]), 229 "bar", 230 "$1$2", 231 "foo", 232 "(.*).(.*)" 233 ) 234 ) by (bar,foo)`, 235 exp: mustNewVectorAggregationExpr( 236 mustNewLabelReplaceExpr( 237 &RangeAggregationExpr{ 238 Left: &LogRange{ 239 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 240 Interval: 5 * time.Hour, 241 }, 242 Operation: "count_over_time", 243 }, 244 "bar", "$1$2", "foo", "(.*).(.*)", 245 ), 246 "avg", &Grouping{ 247 Without: false, 248 Groups: []string{"bar", "foo"}, 249 }, nil), 250 }, 251 { 252 in: `avg(count_over_time({ foo = "bar" }[5h])) by ()`, 253 exp: mustNewVectorAggregationExpr(&RangeAggregationExpr{ 254 Left: &LogRange{ 255 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 256 Interval: 5 * time.Hour, 257 }, 258 Operation: "count_over_time", 259 }, "avg", &Grouping{ 260 Without: false, 261 Groups: nil, 262 }, nil), 263 }, 264 { 265 in: `max without (bar) (count_over_time({ foo = "bar" }[5h]))`, 266 exp: mustNewVectorAggregationExpr(&RangeAggregationExpr{ 267 Left: &LogRange{ 268 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 269 Interval: 5 * time.Hour, 270 }, 271 Operation: "count_over_time", 272 }, "max", &Grouping{ 273 Without: true, 274 Groups: []string{"bar"}, 275 }, nil), 276 }, 277 { 278 in: `max without () (count_over_time({ foo = "bar" }[5h]))`, 279 exp: mustNewVectorAggregationExpr(&RangeAggregationExpr{ 280 Left: &LogRange{ 281 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 282 Interval: 5 * time.Hour, 283 }, 284 Operation: "count_over_time", 285 }, "max", &Grouping{ 286 Without: true, 287 Groups: nil, 288 }, nil), 289 }, 290 { 291 in: `topk(10,count_over_time({ foo = "bar" }[5h])) without (bar)`, 292 exp: mustNewVectorAggregationExpr(&RangeAggregationExpr{ 293 Left: &LogRange{ 294 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 295 Interval: 5 * time.Hour, 296 }, 297 Operation: "count_over_time", 298 }, "topk", &Grouping{ 299 Without: true, 300 Groups: []string{"bar"}, 301 }, NewStringLabelFilter("10")), 302 }, 303 { 304 in: `bottomk(30 ,sum(rate({ foo = "bar" }[5h])) by (foo))`, 305 exp: mustNewVectorAggregationExpr(mustNewVectorAggregationExpr(&RangeAggregationExpr{ 306 Left: &LogRange{ 307 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 308 Interval: 5 * time.Hour, 309 }, 310 Operation: "rate", 311 }, "sum", &Grouping{ 312 Groups: []string{"foo"}, 313 Without: false, 314 }, nil), "bottomk", nil, 315 NewStringLabelFilter("30")), 316 }, 317 { 318 in: `max( sum(count_over_time({ foo = "bar" }[5h])) without (foo,bar) ) by (foo)`, 319 exp: mustNewVectorAggregationExpr(mustNewVectorAggregationExpr(&RangeAggregationExpr{ 320 Left: &LogRange{ 321 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 322 Interval: 5 * time.Hour, 323 }, 324 Operation: "count_over_time", 325 }, "sum", &Grouping{ 326 Groups: []string{"foo", "bar"}, 327 Without: true, 328 }, nil), "max", &Grouping{ 329 Groups: []string{"foo"}, 330 Without: false, 331 }, nil), 332 }, 333 { 334 in: `unk({ foo = "bar" }[5m])`, 335 err: logqlmodel.NewParseError("syntax error: unexpected IDENTIFIER", 1, 1), 336 }, 337 { 338 in: `absent_over_time({ foo = "bar" }[5h]) by (foo)`, 339 err: logqlmodel.NewParseError("grouping not allowed for absent_over_time aggregation", 0, 0), 340 }, 341 { 342 in: `rate({ foo = "bar" }[5minutes])`, 343 err: logqlmodel.NewParseError(`not a valid duration string: "5minutes"`, 0, 21), 344 }, 345 { 346 in: `label_replace(rate({ foo = "bar" }[5m]),"")`, 347 err: logqlmodel.NewParseError(`syntax error: unexpected ), expecting ,`, 1, 43), 348 }, 349 { 350 in: `label_replace(rate({ foo = "bar" }[5m]),"foo","$1","bar","^^^^x43\\q")`, 351 err: logqlmodel.NewParseError("invalid regex in label_replace: error parsing regexp: invalid escape sequence: `\\q`", 0, 0), 352 }, 353 { 354 in: `rate({ foo = "bar" }[5)`, 355 err: logqlmodel.NewParseError("missing closing ']' in duration", 0, 21), 356 }, 357 { 358 in: `min({ foo = "bar" }[5m])`, 359 err: logqlmodel.NewParseError("syntax error: unexpected RANGE", 0, 20), 360 }, 361 // line filter for ip-matcher 362 { 363 in: `{foo="bar"} |= "baz" |= ip("123.123.123.123")`, 364 exp: newPipelineExpr( 365 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 366 MultiStageExpr{ 367 newNestedLineFilterExpr( 368 newLineFilterExpr(labels.MatchEqual, "", "baz"), 369 newLineFilterExpr(labels.MatchEqual, OpFilterIP, "123.123.123.123"), 370 ), 371 }, 372 ), 373 }, 374 { 375 in: `{ foo = "bar" , ip="foo"}|logfmt|= ip("127.0.0.1")|ip="2.3.4.5"|ip="abc"|ipaddr=ip("4.5.6.7")|ip=ip("6.7.8.9")`, 376 exp: newPipelineExpr( 377 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar"), mustNewMatcher(labels.MatchEqual, "ip", "foo")}), 378 MultiStageExpr{ 379 newLabelParserExpr(OpParserTypeLogfmt, ""), 380 newLineFilterExpr(labels.MatchEqual, OpFilterIP, "127.0.0.1"), 381 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "ip", "2.3.4.5"))), 382 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "ip", "abc"))), 383 newLabelFilterExpr(log.NewIPLabelFilter("4.5.6.7", "ipaddr", log.LabelFilterEqual)), 384 newLabelFilterExpr(log.NewIPLabelFilter("6.7.8.9", "ip", log.LabelFilterEqual)), 385 }, 386 ), 387 }, 388 { 389 in: `{foo="bar"} |= ip("123.123.123.123")`, 390 exp: newPipelineExpr( 391 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 392 MultiStageExpr{ 393 newLineFilterExpr(labels.MatchEqual, OpFilterIP, "123.123.123.123"), 394 }, 395 ), 396 }, 397 { 398 in: `{foo="bar"} |= ip("123.123.123.123")|= "baz"`, 399 exp: newPipelineExpr( 400 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 401 MultiStageExpr{ 402 newNestedLineFilterExpr( 403 newLineFilterExpr(labels.MatchEqual, OpFilterIP, "123.123.123.123"), 404 newLineFilterExpr(labels.MatchEqual, "", "baz"), 405 ), 406 }, 407 ), 408 }, 409 { 410 in: `{foo="bar"} |= ip("123.123.123.123")|= "baz" |=ip("123.123.123.123")`, 411 exp: newPipelineExpr( 412 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 413 MultiStageExpr{ 414 newNestedLineFilterExpr( 415 newNestedLineFilterExpr( 416 newLineFilterExpr(labels.MatchEqual, OpFilterIP, "123.123.123.123"), 417 newLineFilterExpr(labels.MatchEqual, "", "baz"), 418 ), 419 newLineFilterExpr(labels.MatchEqual, OpFilterIP, "123.123.123.123"), 420 ), 421 }, 422 ), 423 }, 424 { 425 in: `{foo="bar"} |= "baz" |= ip("123.123.123.123")`, 426 exp: newPipelineExpr( 427 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 428 MultiStageExpr{ 429 newNestedLineFilterExpr( 430 newLineFilterExpr(labels.MatchEqual, "", "baz"), 431 newLineFilterExpr(labels.MatchEqual, OpFilterIP, "123.123.123.123"), 432 ), 433 }, 434 ), 435 }, 436 { 437 in: `{foo="bar"} != ip("123.123.123.123")`, 438 exp: newPipelineExpr( 439 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 440 MultiStageExpr{ 441 newLineFilterExpr(labels.MatchNotEqual, OpFilterIP, "123.123.123.123"), 442 }, 443 ), 444 }, 445 { 446 in: `{foo="bar"} != ip("123.123.123.123")|= "baz"`, 447 exp: newPipelineExpr( 448 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 449 MultiStageExpr{ 450 newNestedLineFilterExpr( 451 newLineFilterExpr(labels.MatchNotEqual, OpFilterIP, "123.123.123.123"), 452 newLineFilterExpr(labels.MatchEqual, "", "baz"), 453 ), 454 }, 455 ), 456 }, 457 { 458 in: `{foo="bar"} != ip("123.123.123.123")|= "baz" !=ip("123.123.123.123")`, 459 exp: newPipelineExpr( 460 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 461 MultiStageExpr{ 462 newNestedLineFilterExpr( 463 newNestedLineFilterExpr( 464 newLineFilterExpr(labels.MatchNotEqual, OpFilterIP, "123.123.123.123"), 465 newLineFilterExpr(labels.MatchEqual, "", "baz"), 466 ), 467 newLineFilterExpr(labels.MatchNotEqual, OpFilterIP, "123.123.123.123"), 468 ), 469 }, 470 ), 471 }, 472 // label filter for ip-matcher 473 { 474 in: `{ foo = "bar" }|logfmt|addr>=ip("1.2.3.4")`, 475 err: logqlmodel.NewParseError("syntax error: unexpected ip, expecting BYTES or NUMBER or DURATION", 1, 30), 476 }, 477 { 478 in: `{ foo = "bar" }|logfmt|addr>ip("1.2.3.4")`, 479 err: logqlmodel.NewParseError("syntax error: unexpected ip, expecting BYTES or NUMBER or DURATION", 1, 29), 480 }, 481 { 482 in: `{ foo = "bar" }|logfmt|addr<=ip("1.2.3.4")`, 483 err: logqlmodel.NewParseError("syntax error: unexpected ip, expecting BYTES or NUMBER or DURATION", 1, 30), 484 }, 485 { 486 in: `{ foo = "bar" }|logfmt|addr<ip("1.2.3.4")`, 487 err: logqlmodel.NewParseError("syntax error: unexpected ip, expecting BYTES or NUMBER or DURATION", 1, 29), 488 }, 489 { 490 in: `{ foo = "bar" }|logfmt|addr=ip("1.2.3.4")`, 491 exp: newPipelineExpr( 492 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 493 MultiStageExpr{newLabelParserExpr(OpParserTypeLogfmt, ""), newLabelFilterExpr(log.NewIPLabelFilter("1.2.3.4", "addr", log.LabelFilterEqual))}, 494 ), 495 }, 496 { 497 in: `{ foo = "bar" }|logfmt|addr!=ip("1.2.3.4")`, 498 exp: newPipelineExpr( 499 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 500 MultiStageExpr{newLabelParserExpr(OpParserTypeLogfmt, ""), newLabelFilterExpr(log.NewIPLabelFilter("1.2.3.4", "addr", log.LabelFilterNotEqual))}, 501 ), 502 }, 503 { 504 in: `{ foo = "bar" }|logfmt|level="error"|addr=ip("1.2.3.4")`, 505 exp: newPipelineExpr( 506 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 507 MultiStageExpr{ 508 newLabelParserExpr(OpParserTypeLogfmt, ""), 509 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "level", "error"))), 510 newLabelFilterExpr(log.NewIPLabelFilter("1.2.3.4", "addr", log.LabelFilterEqual)), 511 }, 512 ), 513 }, 514 { 515 in: `{ foo = "bar" }|logfmt|level="error"|addr!=ip("1.2.3.4")`, 516 exp: newPipelineExpr( 517 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 518 MultiStageExpr{ 519 newLabelParserExpr(OpParserTypeLogfmt, ""), 520 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "level", "error"))), 521 newLabelFilterExpr(log.NewIPLabelFilter("1.2.3.4", "addr", log.LabelFilterNotEqual)), 522 }, 523 ), 524 }, 525 { 526 in: `{ foo = "bar" }|logfmt|remote_addr=ip("2.3.4.5")|level="error"|addr=ip("1.2.3.4")`, // chain label filters with ip matcher 527 exp: newPipelineExpr( 528 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 529 MultiStageExpr{ 530 newLabelParserExpr(OpParserTypeLogfmt, ""), 531 newLabelFilterExpr(log.NewIPLabelFilter("2.3.4.5", "remote_addr", log.LabelFilterEqual)), 532 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "level", "error"))), 533 newLabelFilterExpr(log.NewIPLabelFilter("1.2.3.4", "addr", log.LabelFilterEqual)), 534 }, 535 ), 536 }, 537 { 538 in: `{ foo = "bar" }|logfmt|remote_addr!=ip("2.3.4.5")|level="error"|addr!=ip("1.2.3.4")`, // chain label filters with ip matcher 539 exp: newPipelineExpr( 540 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 541 MultiStageExpr{ 542 newLabelParserExpr(OpParserTypeLogfmt, ""), 543 newLabelFilterExpr(log.NewIPLabelFilter("2.3.4.5", "remote_addr", log.LabelFilterNotEqual)), 544 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "level", "error"))), 545 newLabelFilterExpr(log.NewIPLabelFilter("1.2.3.4", "addr", log.LabelFilterNotEqual)), 546 }, 547 ), 548 }, 549 { 550 in: `{ foo = "bar" }|logfmt|remote_addr=ip("2.3.4.5")|level="error"|addr!=ip("1.2.3.4")`, // chain label filters with ip matcher 551 exp: newPipelineExpr( 552 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 553 MultiStageExpr{ 554 newLabelParserExpr(OpParserTypeLogfmt, ""), 555 newLabelFilterExpr(log.NewIPLabelFilter("2.3.4.5", "remote_addr", log.LabelFilterEqual)), 556 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "level", "error"))), 557 newLabelFilterExpr(log.NewIPLabelFilter("1.2.3.4", "addr", log.LabelFilterNotEqual)), 558 }, 559 ), 560 }, 561 { 562 in: `{ foo = "bar" }|logfmt|ip="2.3.4.5"`, // just using `ip` as a label name(identifier) should work 563 exp: newPipelineExpr( 564 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 565 MultiStageExpr{ 566 newLabelParserExpr(OpParserTypeLogfmt, ""), 567 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "ip", "2.3.4.5"))), 568 }, 569 ), 570 }, 571 { 572 in: `{ foo = "bar" }|logfmt|ip="2.3.4.5"|ip="abc"`, // just using `ip` as a label name should work with chaining 573 exp: newPipelineExpr( 574 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 575 MultiStageExpr{ 576 newLabelParserExpr(OpParserTypeLogfmt, ""), 577 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "ip", "2.3.4.5"))), 578 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "ip", "abc"))), 579 }, 580 ), 581 }, 582 { 583 in: `{ foo = "bar" }|logfmt|ip="2.3.4.5"|ip="abc"|ipaddr=ip("4.5.6.7")`, // `ip` should work as both label name and filter in same query 584 exp: newPipelineExpr( 585 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 586 MultiStageExpr{ 587 newLabelParserExpr(OpParserTypeLogfmt, ""), 588 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "ip", "2.3.4.5"))), 589 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "ip", "abc"))), 590 newLabelFilterExpr(log.NewIPLabelFilter("4.5.6.7", "ipaddr", log.LabelFilterEqual)), 591 }, 592 ), 593 }, 594 { 595 in: `{ foo = "bar" }|logfmt|ip="2.3.4.5"|ip="abc"|ipaddr=ip("4.5.6.7")|ip=ip("6.7.8.9")`, // `ip` should work as both label name and filter in same query with same name. 596 exp: newPipelineExpr( 597 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 598 MultiStageExpr{ 599 newLabelParserExpr(OpParserTypeLogfmt, ""), 600 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "ip", "2.3.4.5"))), 601 newLabelFilterExpr(log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "ip", "abc"))), 602 newLabelFilterExpr(log.NewIPLabelFilter("4.5.6.7", "ipaddr", log.LabelFilterEqual)), 603 newLabelFilterExpr(log.NewIPLabelFilter("6.7.8.9", "ip", log.LabelFilterEqual)), 604 }, 605 ), 606 }, 607 { 608 in: `sum(3 ,count_over_time({ foo = "bar" }[5h]))`, 609 err: logqlmodel.NewParseError("unsupported parameter for operation sum(3,", 0, 0), 610 }, 611 { 612 in: `topk(count_over_time({ foo = "bar" }[5h]))`, 613 err: logqlmodel.NewParseError("parameter required for operation topk", 0, 0), 614 }, 615 { 616 in: `bottomk(he,count_over_time({ foo = "bar" }[5h]))`, 617 err: logqlmodel.NewParseError("syntax error: unexpected IDENTIFIER", 1, 9), 618 }, 619 { 620 in: `bottomk(1.2,count_over_time({ foo = "bar" }[5h]))`, 621 err: logqlmodel.NewParseError("invalid parameter bottomk(1.2,", 0, 0), 622 }, 623 { 624 in: `stddev({ foo = "bar" })`, 625 err: logqlmodel.NewParseError("syntax error: unexpected )", 1, 23), 626 }, 627 { 628 in: `{ foo = "bar", bar != "baz" }`, 629 exp: &MatchersExpr{Mts: []*labels.Matcher{ 630 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 631 mustNewMatcher(labels.MatchNotEqual, "bar", "baz"), 632 }}, 633 }, 634 { 635 in: `{foo="bar"} |= "baz"`, 636 exp: newPipelineExpr( 637 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 638 MultiStageExpr{newLineFilterExpr(labels.MatchEqual, "", "baz")}, 639 ), 640 }, 641 { 642 in: `{foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap"`, 643 exp: newPipelineExpr( 644 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 645 MultiStageExpr{ 646 newNestedLineFilterExpr( 647 newNestedLineFilterExpr( 648 newNestedLineFilterExpr( 649 newLineFilterExpr(labels.MatchEqual, "", "baz"), 650 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 651 ), 652 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 653 ), 654 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 655 ), 656 }, 657 ), 658 }, 659 { 660 in: `count_over_time(({foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap")[5m])`, 661 exp: newRangeAggregationExpr( 662 &LogRange{ 663 Left: newPipelineExpr( 664 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 665 MultiStageExpr{ 666 newNestedLineFilterExpr( 667 newNestedLineFilterExpr( 668 newNestedLineFilterExpr( 669 newLineFilterExpr(labels.MatchEqual, "", "baz"), 670 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 671 ), 672 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 673 ), 674 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 675 ), 676 }, 677 ), 678 Interval: 5 * time.Minute, 679 }, OpRangeTypeCount, nil, nil), 680 }, 681 { 682 in: `bytes_over_time(({foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap")[5m])`, 683 exp: newRangeAggregationExpr( 684 &LogRange{ 685 Left: newPipelineExpr( 686 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 687 MultiStageExpr{ 688 newNestedLineFilterExpr( 689 newNestedLineFilterExpr( 690 newNestedLineFilterExpr( 691 newLineFilterExpr(labels.MatchEqual, "", "baz"), 692 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 693 ), 694 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 695 ), 696 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 697 ), 698 }, 699 ), 700 Interval: 5 * time.Minute, 701 }, OpRangeTypeBytes, nil, nil), 702 }, 703 { 704 in: `bytes_over_time(({foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap" | unpack)[5m])`, 705 exp: newRangeAggregationExpr( 706 &LogRange{ 707 Left: newPipelineExpr( 708 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 709 MultiStageExpr{ 710 newNestedLineFilterExpr( 711 newNestedLineFilterExpr( 712 newNestedLineFilterExpr( 713 newLineFilterExpr(labels.MatchEqual, "", "baz"), 714 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 715 ), 716 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 717 ), 718 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 719 ), 720 newLabelParserExpr(OpParserTypeUnpack, ""), 721 }, 722 ), 723 Interval: 5 * time.Minute, 724 }, OpRangeTypeBytes, nil, nil), 725 }, 726 { 727 in: ` 728 label_replace( 729 bytes_over_time(({foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap")[5m]), 730 "buzz", 731 "$2", 732 "bar", 733 "(.*):(.*)" 734 ) 735 `, 736 exp: mustNewLabelReplaceExpr( 737 newRangeAggregationExpr( 738 &LogRange{ 739 Left: newPipelineExpr( 740 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 741 MultiStageExpr{ 742 newNestedLineFilterExpr( 743 newNestedLineFilterExpr( 744 newNestedLineFilterExpr( 745 newLineFilterExpr(labels.MatchEqual, "", "baz"), 746 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 747 ), 748 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 749 ), 750 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 751 ), 752 }, 753 ), 754 Interval: 5 * time.Minute, 755 }, OpRangeTypeBytes, nil, nil), 756 "buzz", 757 "$2", 758 "bar", 759 "(.*):(.*)", 760 ), 761 }, 762 { 763 in: `sum(count_over_time(({foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap")[5m])) by (foo)`, 764 exp: mustNewVectorAggregationExpr(newRangeAggregationExpr( 765 &LogRange{ 766 Left: newPipelineExpr( 767 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 768 MultiStageExpr{ 769 newNestedLineFilterExpr( 770 newNestedLineFilterExpr( 771 newNestedLineFilterExpr( 772 newLineFilterExpr(labels.MatchEqual, "", "baz"), 773 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 774 ), 775 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 776 ), 777 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 778 ), 779 }, 780 ), 781 Interval: 5 * time.Minute, 782 }, OpRangeTypeCount, nil, nil), 783 "sum", 784 &Grouping{ 785 Without: false, 786 Groups: []string{"foo"}, 787 }, 788 nil), 789 }, 790 { 791 in: `sum(bytes_rate(({foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap")[5m])) by (foo)`, 792 exp: mustNewVectorAggregationExpr(newRangeAggregationExpr( 793 &LogRange{ 794 Left: newPipelineExpr( 795 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 796 MultiStageExpr{ 797 newNestedLineFilterExpr( 798 newNestedLineFilterExpr( 799 newNestedLineFilterExpr( 800 newLineFilterExpr(labels.MatchEqual, "", "baz"), 801 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 802 ), 803 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 804 ), 805 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 806 ), 807 }, 808 ), 809 Interval: 5 * time.Minute, 810 }, OpRangeTypeBytesRate, nil, nil), 811 "sum", 812 &Grouping{ 813 Without: false, 814 Groups: []string{"foo"}, 815 }, 816 nil), 817 }, 818 { 819 in: `topk(5,count_over_time(({foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap")[5m])) without (foo)`, 820 exp: mustNewVectorAggregationExpr(newRangeAggregationExpr( 821 &LogRange{ 822 Left: newPipelineExpr( 823 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 824 MultiStageExpr{ 825 newNestedLineFilterExpr( 826 newNestedLineFilterExpr( 827 newNestedLineFilterExpr( 828 newLineFilterExpr(labels.MatchEqual, "", "baz"), 829 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 830 ), 831 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 832 ), 833 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 834 ), 835 }, 836 ), 837 Interval: 5 * time.Minute, 838 }, OpRangeTypeCount, nil, nil), 839 "topk", 840 &Grouping{ 841 Without: true, 842 Groups: []string{"foo"}, 843 }, 844 NewStringLabelFilter("5")), 845 }, 846 { 847 in: `topk(5,sum(rate(({foo="bar"} |= "baz" |~ "blip" != "flip" !~ "flap")[5m])) by (app))`, 848 exp: mustNewVectorAggregationExpr( 849 mustNewVectorAggregationExpr( 850 newRangeAggregationExpr( 851 &LogRange{ 852 Left: newPipelineExpr( 853 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 854 MultiStageExpr{ 855 newNestedLineFilterExpr( 856 newNestedLineFilterExpr( 857 newNestedLineFilterExpr( 858 newLineFilterExpr(labels.MatchEqual, "", "baz"), 859 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 860 ), 861 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 862 ), 863 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 864 ), 865 }, 866 ), 867 Interval: 5 * time.Minute, 868 }, OpRangeTypeRate, nil, nil), 869 "sum", 870 &Grouping{ 871 Without: false, 872 Groups: []string{"app"}, 873 }, 874 nil), 875 "topk", 876 nil, 877 NewStringLabelFilter("5")), 878 }, 879 { 880 in: `count_over_time({foo="bar"}[5m] |= "baz" |~ "blip" != "flip" !~ "flap")`, 881 exp: newRangeAggregationExpr( 882 &LogRange{ 883 Left: newPipelineExpr( 884 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 885 MultiStageExpr{ 886 newNestedLineFilterExpr( 887 newNestedLineFilterExpr( 888 newNestedLineFilterExpr( 889 newLineFilterExpr(labels.MatchEqual, "", "baz"), 890 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 891 ), 892 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 893 ), 894 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 895 ), 896 }, 897 ), 898 Interval: 5 * time.Minute, 899 }, OpRangeTypeCount, nil, nil), 900 }, 901 { 902 in: `sum(count_over_time({foo="bar"}[5m] |= "baz" |~ "blip" != "flip" !~ "flap")) by (foo)`, 903 exp: mustNewVectorAggregationExpr(newRangeAggregationExpr( 904 &LogRange{ 905 Left: newPipelineExpr( 906 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 907 MultiStageExpr{ 908 newNestedLineFilterExpr( 909 newNestedLineFilterExpr( 910 newNestedLineFilterExpr( 911 newLineFilterExpr(labels.MatchEqual, "", "baz"), 912 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 913 ), 914 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 915 ), 916 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 917 ), 918 }, 919 ), 920 Interval: 5 * time.Minute, 921 }, OpRangeTypeCount, nil, nil), 922 "sum", 923 &Grouping{ 924 Without: false, 925 Groups: []string{"foo"}, 926 }, 927 nil), 928 }, 929 { 930 in: `topk(5,count_over_time({foo="bar"}[5m] |= "baz" |~ "blip" != "flip" !~ "flap")) without (foo)`, 931 exp: mustNewVectorAggregationExpr(newRangeAggregationExpr( 932 &LogRange{ 933 Left: newPipelineExpr( 934 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 935 MultiStageExpr{ 936 newNestedLineFilterExpr( 937 newNestedLineFilterExpr( 938 newNestedLineFilterExpr( 939 newLineFilterExpr(labels.MatchEqual, "", "baz"), 940 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 941 ), 942 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 943 ), 944 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 945 ), 946 }, 947 ), 948 Interval: 5 * time.Minute, 949 }, OpRangeTypeCount, nil, nil), 950 "topk", 951 &Grouping{ 952 Without: true, 953 Groups: []string{"foo"}, 954 }, 955 NewStringLabelFilter("5")), 956 }, 957 { 958 in: `topk(5,sum(rate({foo="bar"}[5m] |= "baz" |~ "blip" != "flip" !~ "flap")) by (app))`, 959 exp: mustNewVectorAggregationExpr( 960 mustNewVectorAggregationExpr( 961 newRangeAggregationExpr( 962 &LogRange{ 963 Left: newPipelineExpr( 964 newMatcherExpr([]*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}), 965 MultiStageExpr{ 966 newNestedLineFilterExpr( 967 newNestedLineFilterExpr( 968 newNestedLineFilterExpr( 969 newLineFilterExpr(labels.MatchEqual, "", "baz"), 970 newLineFilterExpr(labels.MatchRegexp, "", "blip"), 971 ), 972 newLineFilterExpr(labels.MatchNotEqual, "", "flip"), 973 ), 974 newLineFilterExpr(labels.MatchNotRegexp, "", "flap"), 975 ), 976 }, 977 ), 978 Interval: 5 * time.Minute, 979 }, OpRangeTypeRate, nil, nil), 980 "sum", 981 &Grouping{ 982 Without: false, 983 Groups: []string{"app"}, 984 }, 985 nil), 986 "topk", 987 nil, 988 NewStringLabelFilter("5")), 989 }, 990 { 991 in: `{foo="bar}`, 992 err: logqlmodel.NewParseError("literal not terminated", 1, 6), 993 }, 994 { 995 in: `{foo="bar"`, 996 err: logqlmodel.NewParseError("syntax error: unexpected $end, expecting } or ,", 1, 11), 997 }, 998 999 { 1000 in: `{foo="bar"} |~`, 1001 err: logqlmodel.NewParseError("syntax error: unexpected $end, expecting STRING or ip", 1, 15), 1002 }, 1003 1004 { 1005 in: `{foo="bar"} "foo"`, 1006 err: logqlmodel.NewParseError("syntax error: unexpected STRING", 1, 13), 1007 }, 1008 { 1009 in: `{foo="bar"} foo`, 1010 err: logqlmodel.NewParseError("syntax error: unexpected IDENTIFIER", 1, 13), 1011 }, 1012 { 1013 // require left associativity 1014 in: ` 1015 sum(count_over_time({foo="bar"}[5m])) by (foo) / 1016 sum(count_over_time({foo="bar"}[5m])) by (foo) / 1017 sum(count_over_time({foo="bar"}[5m])) by (foo) 1018 `, 1019 exp: mustNewBinOpExpr( 1020 OpTypeDiv, 1021 &BinOpOptions{ 1022 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1023 }, 1024 mustNewBinOpExpr( 1025 OpTypeDiv, 1026 &BinOpOptions{ 1027 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1028 }, 1029 mustNewVectorAggregationExpr(newRangeAggregationExpr( 1030 &LogRange{ 1031 Left: &MatchersExpr{ 1032 Mts: []*labels.Matcher{ 1033 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 1034 }, 1035 }, 1036 Interval: 5 * time.Minute, 1037 }, OpRangeTypeCount, nil, nil), 1038 "sum", 1039 &Grouping{ 1040 Without: false, 1041 Groups: []string{"foo"}, 1042 }, 1043 nil, 1044 ), 1045 mustNewVectorAggregationExpr(newRangeAggregationExpr( 1046 &LogRange{ 1047 Left: &MatchersExpr{ 1048 Mts: []*labels.Matcher{ 1049 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 1050 }, 1051 }, 1052 Interval: 5 * time.Minute, 1053 }, OpRangeTypeCount, nil, nil), 1054 "sum", 1055 &Grouping{ 1056 Without: false, 1057 Groups: []string{"foo"}, 1058 }, 1059 nil, 1060 ), 1061 ), 1062 mustNewVectorAggregationExpr(newRangeAggregationExpr( 1063 &LogRange{ 1064 Left: &MatchersExpr{ 1065 Mts: []*labels.Matcher{ 1066 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 1067 }, 1068 }, 1069 Interval: 5 * time.Minute, 1070 }, OpRangeTypeCount, nil, nil), 1071 "sum", 1072 &Grouping{ 1073 Without: false, 1074 Groups: []string{"foo"}, 1075 }, 1076 nil, 1077 ), 1078 ), 1079 }, 1080 { 1081 in: ` 1082 sum(count_over_time({foo="bar"}[5m])) by (foo) ^ 1083 sum(count_over_time({foo="bar"}[5m])) by (foo) / 1084 sum(count_over_time({foo="bar"}[5m])) by (foo) 1085 `, 1086 exp: mustNewBinOpExpr( 1087 OpTypeDiv, 1088 &BinOpOptions{ 1089 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1090 }, 1091 mustNewBinOpExpr( 1092 OpTypePow, 1093 &BinOpOptions{ 1094 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1095 }, 1096 mustNewVectorAggregationExpr(newRangeAggregationExpr( 1097 &LogRange{ 1098 Left: &MatchersExpr{ 1099 Mts: []*labels.Matcher{ 1100 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 1101 }, 1102 }, 1103 Interval: 5 * time.Minute, 1104 }, OpRangeTypeCount, nil, nil), 1105 "sum", 1106 &Grouping{ 1107 Without: false, 1108 Groups: []string{"foo"}, 1109 }, 1110 nil, 1111 ), 1112 mustNewVectorAggregationExpr(newRangeAggregationExpr( 1113 &LogRange{ 1114 Left: &MatchersExpr{ 1115 Mts: []*labels.Matcher{ 1116 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 1117 }, 1118 }, 1119 Interval: 5 * time.Minute, 1120 }, OpRangeTypeCount, nil, nil), 1121 "sum", 1122 &Grouping{ 1123 Without: false, 1124 Groups: []string{"foo"}, 1125 }, 1126 nil, 1127 ), 1128 ), 1129 mustNewVectorAggregationExpr(newRangeAggregationExpr( 1130 &LogRange{ 1131 Left: &MatchersExpr{ 1132 Mts: []*labels.Matcher{ 1133 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 1134 }, 1135 }, 1136 Interval: 5 * time.Minute, 1137 }, OpRangeTypeCount, nil, nil), 1138 "sum", 1139 &Grouping{ 1140 Without: false, 1141 Groups: []string{"foo"}, 1142 }, 1143 nil, 1144 ), 1145 ), 1146 }, 1147 { 1148 // operator precedence before left associativity 1149 in: ` 1150 sum(count_over_time({foo="bar"}[5m])) by (foo) + 1151 sum(count_over_time({foo="bar"}[5m])) by (foo) / 1152 sum(count_over_time({foo="bar"}[5m])) by (foo) 1153 `, 1154 exp: mustNewBinOpExpr( 1155 OpTypeAdd, 1156 &BinOpOptions{ 1157 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1158 }, 1159 mustNewVectorAggregationExpr(newRangeAggregationExpr( 1160 &LogRange{ 1161 Left: &MatchersExpr{ 1162 Mts: []*labels.Matcher{ 1163 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 1164 }, 1165 }, 1166 Interval: 5 * time.Minute, 1167 }, OpRangeTypeCount, nil, nil), 1168 "sum", 1169 &Grouping{ 1170 Without: false, 1171 Groups: []string{"foo"}, 1172 }, 1173 nil, 1174 ), 1175 mustNewBinOpExpr( 1176 OpTypeDiv, 1177 &BinOpOptions{ 1178 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1179 }, 1180 mustNewVectorAggregationExpr(newRangeAggregationExpr( 1181 &LogRange{ 1182 Left: &MatchersExpr{ 1183 Mts: []*labels.Matcher{ 1184 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 1185 }, 1186 }, 1187 Interval: 5 * time.Minute, 1188 }, OpRangeTypeCount, nil, nil), 1189 "sum", 1190 &Grouping{ 1191 Without: false, 1192 Groups: []string{"foo"}, 1193 }, 1194 nil, 1195 ), 1196 mustNewVectorAggregationExpr(newRangeAggregationExpr( 1197 &LogRange{ 1198 Left: &MatchersExpr{ 1199 Mts: []*labels.Matcher{ 1200 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 1201 }, 1202 }, 1203 Interval: 5 * time.Minute, 1204 }, OpRangeTypeCount, nil, nil), 1205 "sum", 1206 &Grouping{ 1207 Without: false, 1208 Groups: []string{"foo"}, 1209 }, 1210 nil, 1211 ), 1212 ), 1213 ), 1214 }, 1215 { 1216 in: `sum by (job) ( 1217 count_over_time({namespace="tns"} |= "level=error"[5m]) 1218 / 1219 count_over_time({namespace="tns"}[5m]) 1220 )`, 1221 exp: mustNewVectorAggregationExpr( 1222 mustNewBinOpExpr(OpTypeDiv, 1223 &BinOpOptions{ 1224 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1225 }, 1226 newRangeAggregationExpr( 1227 &LogRange{ 1228 Left: newPipelineExpr( 1229 newMatcherExpr([]*labels.Matcher{ 1230 mustNewMatcher(labels.MatchEqual, "namespace", "tns"), 1231 }), 1232 MultiStageExpr{ 1233 newLineFilterExpr(labels.MatchEqual, "", "level=error"), 1234 }), 1235 Interval: 5 * time.Minute, 1236 }, OpRangeTypeCount, nil, nil), 1237 newRangeAggregationExpr( 1238 &LogRange{ 1239 Left: &MatchersExpr{ 1240 Mts: []*labels.Matcher{ 1241 mustNewMatcher(labels.MatchEqual, "namespace", "tns"), 1242 }, 1243 }, 1244 Interval: 5 * time.Minute, 1245 }, OpRangeTypeCount, nil, nil)), OpTypeSum, &Grouping{Groups: []string{"job"}}, nil), 1246 }, 1247 { 1248 in: `sum by (job) ( 1249 count_over_time({namespace="tns"} |= "level=error"[5m]) 1250 / 1251 count_over_time({namespace="tns"}[5m]) 1252 ) * 100`, 1253 exp: mustNewBinOpExpr(OpTypeMul, &BinOpOptions{ 1254 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1255 }, mustNewVectorAggregationExpr( 1256 mustNewBinOpExpr(OpTypeDiv, 1257 &BinOpOptions{ 1258 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1259 }, 1260 newRangeAggregationExpr( 1261 &LogRange{ 1262 Left: newPipelineExpr( 1263 newMatcherExpr([]*labels.Matcher{ 1264 mustNewMatcher(labels.MatchEqual, "namespace", "tns"), 1265 }), 1266 MultiStageExpr{ 1267 newLineFilterExpr(labels.MatchEqual, "", "level=error"), 1268 }), 1269 Interval: 5 * time.Minute, 1270 }, OpRangeTypeCount, nil, nil), 1271 newRangeAggregationExpr( 1272 &LogRange{ 1273 Left: &MatchersExpr{ 1274 Mts: []*labels.Matcher{ 1275 mustNewMatcher(labels.MatchEqual, "namespace", "tns"), 1276 }, 1277 }, 1278 Interval: 5 * time.Minute, 1279 }, OpRangeTypeCount, nil, nil)), OpTypeSum, &Grouping{Groups: []string{"job"}}, nil), 1280 mustNewLiteralExpr("100", false), 1281 ), 1282 }, 1283 { 1284 // reduces binop with two literalExprs 1285 in: `sum(count_over_time({foo="bar"}[5m])) by (foo) + 1 / 2`, 1286 exp: mustNewBinOpExpr( 1287 OpTypeAdd, 1288 &BinOpOptions{ 1289 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1290 }, 1291 mustNewVectorAggregationExpr( 1292 newRangeAggregationExpr( 1293 &LogRange{ 1294 Left: &MatchersExpr{ 1295 Mts: []*labels.Matcher{ 1296 mustNewMatcher(labels.MatchEqual, "foo", "bar"), 1297 }, 1298 }, 1299 Interval: 5 * time.Minute, 1300 }, OpRangeTypeCount, nil, nil), 1301 "sum", 1302 &Grouping{ 1303 Without: false, 1304 Groups: []string{"foo"}, 1305 }, 1306 nil, 1307 ), 1308 &LiteralExpr{Val: 0.5}, 1309 ), 1310 }, 1311 { 1312 // test signs 1313 in: `1 + -2 / 1`, 1314 exp: mustNewBinOpExpr( 1315 OpTypeAdd, 1316 &BinOpOptions{ 1317 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1318 }, 1319 &LiteralExpr{Val: 1}, 1320 mustNewBinOpExpr(OpTypeDiv, &BinOpOptions{ 1321 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1322 }, &LiteralExpr{Val: -2}, &LiteralExpr{Val: 1}), 1323 ), 1324 }, 1325 { 1326 // test signs/ops with equal associativity 1327 in: `1 + 1 - -1`, 1328 exp: mustNewBinOpExpr( 1329 OpTypeSub, 1330 &BinOpOptions{ 1331 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1332 }, 1333 mustNewBinOpExpr(OpTypeAdd, &BinOpOptions{ 1334 VectorMatching: &VectorMatching{Card: CardOneToOne}, 1335 }, &LiteralExpr{Val: 1}, &LiteralExpr{Val: 1}), 1336 &LiteralExpr{Val: -1}, 1337 ), 1338 }, 1339 { 1340 in: `{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200)`, 1341 exp: &PipelineExpr{ 1342 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1343 MultiStages: MultiStageExpr{ 1344 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1345 newLabelParserExpr(OpParserTypeJSON, ""), 1346 &LabelFilterExpr{ 1347 LabelFilterer: log.NewOrLabelFilter( 1348 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1349 log.NewAndLabelFilter( 1350 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1351 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1352 ), 1353 ), 1354 }, 1355 }, 1356 }, 1357 }, 1358 { 1359 in: `{app="foo"} |= "bar" | unpack | json | latency >= 250ms or ( status_code < 500 and status_code > 200)`, 1360 exp: &PipelineExpr{ 1361 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1362 MultiStages: MultiStageExpr{ 1363 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1364 newLabelParserExpr(OpParserTypeUnpack, ""), 1365 newLabelParserExpr(OpParserTypeJSON, ""), 1366 &LabelFilterExpr{ 1367 LabelFilterer: log.NewOrLabelFilter( 1368 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1369 log.NewAndLabelFilter( 1370 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1371 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1372 ), 1373 ), 1374 }, 1375 }, 1376 }, 1377 }, 1378 { 1379 in: `{app="foo"} |= "bar" | json | (duration > 1s or status!= 200) and method!="POST"`, 1380 exp: &PipelineExpr{ 1381 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1382 MultiStages: MultiStageExpr{ 1383 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1384 newLabelParserExpr(OpParserTypeJSON, ""), 1385 &LabelFilterExpr{ 1386 LabelFilterer: log.NewAndLabelFilter( 1387 log.NewOrLabelFilter( 1388 log.NewDurationLabelFilter(log.LabelFilterGreaterThan, "duration", 1*time.Second), 1389 log.NewNumericLabelFilter(log.LabelFilterNotEqual, "status", 200.0), 1390 ), 1391 log.NewStringLabelFilter(mustNewMatcher(labels.MatchNotEqual, "method", "POST")), 1392 ), 1393 }, 1394 }, 1395 }, 1396 }, 1397 { 1398 in: `{app="foo"} |= "bar" | pattern "<foo> bar <buzz>" | (duration > 1s or status!= 200) and method!="POST"`, 1399 exp: &PipelineExpr{ 1400 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1401 MultiStages: MultiStageExpr{ 1402 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1403 newLabelParserExpr(OpParserTypePattern, "<foo> bar <buzz>"), 1404 &LabelFilterExpr{ 1405 LabelFilterer: log.NewAndLabelFilter( 1406 log.NewOrLabelFilter( 1407 log.NewDurationLabelFilter(log.LabelFilterGreaterThan, "duration", 1*time.Second), 1408 log.NewNumericLabelFilter(log.LabelFilterNotEqual, "status", 200.0), 1409 ), 1410 log.NewStringLabelFilter(mustNewMatcher(labels.MatchNotEqual, "method", "POST")), 1411 ), 1412 }, 1413 }, 1414 }, 1415 }, 1416 { 1417 in: `{app="foo"} |= "bar" | json | ( status_code < 500 and status_code > 200) or latency >= 250ms `, 1418 exp: &PipelineExpr{ 1419 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1420 MultiStages: MultiStageExpr{ 1421 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1422 newLabelParserExpr(OpParserTypeJSON, ""), 1423 &LabelFilterExpr{ 1424 LabelFilterer: log.NewOrLabelFilter( 1425 log.NewAndLabelFilter( 1426 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1427 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1428 ), 1429 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1430 ), 1431 }, 1432 }, 1433 }, 1434 }, 1435 { 1436 in: `{app="foo"} |= "bar" | json | ( status_code < 500 or status_code > 200) and latency >= 250ms `, 1437 exp: &PipelineExpr{ 1438 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1439 MultiStages: MultiStageExpr{ 1440 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1441 newLabelParserExpr(OpParserTypeJSON, ""), 1442 &LabelFilterExpr{ 1443 LabelFilterer: log.NewAndLabelFilter( 1444 log.NewOrLabelFilter( 1445 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1446 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1447 ), 1448 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1449 ), 1450 }, 1451 }, 1452 }, 1453 }, 1454 { 1455 in: `{app="foo"} |= "bar" | json | status_code < 500 or status_code > 200 and latency >= 250ms `, 1456 exp: &PipelineExpr{ 1457 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1458 MultiStages: MultiStageExpr{ 1459 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1460 newLabelParserExpr(OpParserTypeJSON, ""), 1461 &LabelFilterExpr{ 1462 LabelFilterer: log.NewOrLabelFilter( 1463 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1464 log.NewAndLabelFilter( 1465 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1466 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1467 ), 1468 ), 1469 }, 1470 }, 1471 }, 1472 }, 1473 { 1474 in: `{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1475 | foo="bar" buzz!="blip", blop=~"boop" or fuzz==5`, 1476 exp: &PipelineExpr{ 1477 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1478 MultiStages: MultiStageExpr{ 1479 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1480 newLabelParserExpr(OpParserTypeJSON, ""), 1481 &LabelFilterExpr{ 1482 LabelFilterer: log.NewOrLabelFilter( 1483 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1484 log.NewAndLabelFilter( 1485 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1486 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1487 ), 1488 ), 1489 }, 1490 &LabelFilterExpr{ 1491 LabelFilterer: log.NewAndLabelFilter( 1492 log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "foo", "bar")), 1493 log.NewAndLabelFilter( 1494 log.NewStringLabelFilter(mustNewMatcher(labels.MatchNotEqual, "buzz", "blip")), 1495 log.NewOrLabelFilter( 1496 log.NewStringLabelFilter(mustNewMatcher(labels.MatchRegexp, "blop", "boop")), 1497 log.NewNumericLabelFilter(log.LabelFilterEqual, "fuzz", 5), 1498 ), 1499 ), 1500 ), 1501 }, 1502 }, 1503 }, 1504 }, 1505 { 1506 in: `{app="foo"} |= "bar" | line_format "blip{{ .foo }}blop"`, 1507 exp: &PipelineExpr{ 1508 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1509 MultiStages: MultiStageExpr{ 1510 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1511 newLineFmtExpr("blip{{ .foo }}blop"), 1512 }, 1513 }, 1514 }, 1515 { 1516 in: `{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1517 | line_format "blip{{ .foo }}blop {{.status_code}}"`, 1518 exp: &PipelineExpr{ 1519 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1520 MultiStages: MultiStageExpr{ 1521 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1522 newLabelParserExpr(OpParserTypeJSON, ""), 1523 &LabelFilterExpr{ 1524 LabelFilterer: log.NewOrLabelFilter( 1525 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1526 log.NewAndLabelFilter( 1527 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1528 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1529 ), 1530 ), 1531 }, 1532 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 1533 }, 1534 }, 1535 }, 1536 { 1537 in: `{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1538 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}"`, 1539 exp: &PipelineExpr{ 1540 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1541 MultiStages: MultiStageExpr{ 1542 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1543 newLabelParserExpr(OpParserTypeJSON, ""), 1544 &LabelFilterExpr{ 1545 LabelFilterer: log.NewOrLabelFilter( 1546 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1547 log.NewAndLabelFilter( 1548 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1549 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1550 ), 1551 ), 1552 }, 1553 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 1554 newLabelFmtExpr([]log.LabelFmt{ 1555 log.NewRenameLabelFmt("foo", "bar"), 1556 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 1557 }), 1558 }, 1559 }, 1560 }, 1561 { 1562 in: `count_over_time({app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1563 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}"[5m])`, 1564 exp: newRangeAggregationExpr( 1565 newLogRange(&PipelineExpr{ 1566 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1567 MultiStages: MultiStageExpr{ 1568 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1569 newLabelParserExpr(OpParserTypeJSON, ""), 1570 &LabelFilterExpr{ 1571 LabelFilterer: log.NewOrLabelFilter( 1572 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1573 log.NewAndLabelFilter( 1574 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1575 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1576 ), 1577 ), 1578 }, 1579 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 1580 newLabelFmtExpr([]log.LabelFmt{ 1581 log.NewRenameLabelFmt("foo", "bar"), 1582 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 1583 }), 1584 }, 1585 }, 1586 5*time.Minute, 1587 nil, nil), 1588 OpRangeTypeCount, 1589 nil, 1590 nil, 1591 ), 1592 }, 1593 { 1594 in: "{app=~\"\xa0\xa1\"}", 1595 exp: nil, 1596 err: logqlmodel.NewParseError("invalid UTF-8 encoding", 1, 7), 1597 }, 1598 { 1599 in: `sum_over_time({app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1600 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}"[5m])`, 1601 exp: nil, 1602 err: logqlmodel.NewParseError("invalid aggregation sum_over_time without unwrap", 0, 0), 1603 }, 1604 { 1605 in: `count_over_time({app="foo"} |= "foo" | json | unwrap foo [5m])`, 1606 exp: nil, 1607 err: logqlmodel.NewParseError("invalid aggregation count_over_time with unwrap", 0, 0), 1608 }, 1609 { 1610 in: `{app="foo"} |= "bar" | json | status_code < 500 or status_code > 200 and size >= 2.5KiB `, 1611 exp: &PipelineExpr{ 1612 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1613 MultiStages: MultiStageExpr{ 1614 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1615 newLabelParserExpr(OpParserTypeJSON, ""), 1616 &LabelFilterExpr{ 1617 LabelFilterer: log.NewOrLabelFilter( 1618 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1619 log.NewAndLabelFilter( 1620 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1621 log.NewBytesLabelFilter(log.LabelFilterGreaterThanOrEqual, "size", 2560), 1622 ), 1623 ), 1624 }, 1625 }, 1626 }, 1627 }, 1628 { 1629 in: `stdvar_over_time({app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1630 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m])`, 1631 exp: newRangeAggregationExpr( 1632 newLogRange(&PipelineExpr{ 1633 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1634 MultiStages: MultiStageExpr{ 1635 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1636 newLabelParserExpr(OpParserTypeJSON, ""), 1637 &LabelFilterExpr{ 1638 LabelFilterer: log.NewOrLabelFilter( 1639 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1640 log.NewAndLabelFilter( 1641 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1642 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1643 ), 1644 ), 1645 }, 1646 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 1647 newLabelFmtExpr([]log.LabelFmt{ 1648 log.NewRenameLabelFmt("foo", "bar"), 1649 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 1650 }), 1651 }, 1652 }, 1653 5*time.Minute, 1654 newUnwrapExpr("foo", ""), 1655 nil), 1656 OpRangeTypeStdvar, nil, nil, 1657 ), 1658 }, 1659 { 1660 in: `stdvar_over_time({app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1661 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap duration(foo) [5m])`, 1662 exp: newRangeAggregationExpr( 1663 newLogRange(&PipelineExpr{ 1664 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1665 MultiStages: MultiStageExpr{ 1666 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1667 newLabelParserExpr(OpParserTypeJSON, ""), 1668 &LabelFilterExpr{ 1669 LabelFilterer: log.NewOrLabelFilter( 1670 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1671 log.NewAndLabelFilter( 1672 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1673 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1674 ), 1675 ), 1676 }, 1677 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 1678 newLabelFmtExpr([]log.LabelFmt{ 1679 log.NewRenameLabelFmt("foo", "bar"), 1680 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 1681 }), 1682 }, 1683 }, 1684 5*time.Minute, 1685 newUnwrapExpr("foo", OpConvDuration), 1686 nil), 1687 OpRangeTypeStdvar, nil, nil, 1688 ), 1689 }, 1690 { 1691 in: `sum_over_time({namespace="tns"} |= "level=error" | json |foo>=5,bar<25ms| unwrap bytes(foo) [5m])`, 1692 exp: newRangeAggregationExpr( 1693 newLogRange(&PipelineExpr{ 1694 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "namespace", Value: "tns"}}), 1695 MultiStages: MultiStageExpr{ 1696 newLineFilterExpr(labels.MatchEqual, "", "level=error"), 1697 newLabelParserExpr(OpParserTypeJSON, ""), 1698 &LabelFilterExpr{ 1699 LabelFilterer: log.NewAndLabelFilter( 1700 log.NewNumericLabelFilter(log.LabelFilterGreaterThanOrEqual, "foo", 5), 1701 log.NewDurationLabelFilter(log.LabelFilterLesserThan, "bar", 25*time.Millisecond), 1702 ), 1703 }, 1704 }, 1705 }, 1706 5*time.Minute, 1707 newUnwrapExpr("foo", OpConvBytes), 1708 nil), 1709 OpRangeTypeSum, nil, nil, 1710 ), 1711 }, 1712 { 1713 in: `sum_over_time({namespace="tns"} |= "level=error" | json |foo>=5,bar<25ms| unwrap bytes(foo) [5m] offset 5m)`, 1714 exp: newRangeAggregationExpr( 1715 newLogRange(&PipelineExpr{ 1716 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "namespace", Value: "tns"}}), 1717 MultiStages: MultiStageExpr{ 1718 newLineFilterExpr(labels.MatchEqual, "", "level=error"), 1719 newLabelParserExpr(OpParserTypeJSON, ""), 1720 &LabelFilterExpr{ 1721 LabelFilterer: log.NewAndLabelFilter( 1722 log.NewNumericLabelFilter(log.LabelFilterGreaterThanOrEqual, "foo", 5), 1723 log.NewDurationLabelFilter(log.LabelFilterLesserThan, "bar", 25*time.Millisecond), 1724 ), 1725 }, 1726 }, 1727 }, 1728 5*time.Minute, 1729 newUnwrapExpr("foo", OpConvBytes), 1730 newOffsetExpr(5*time.Minute)), 1731 OpRangeTypeSum, nil, nil, 1732 ), 1733 }, 1734 { 1735 in: `sum_over_time({namespace="tns"} |= "level=error" | json |foo>=5,bar<25ms| unwrap latency [5m])`, 1736 exp: newRangeAggregationExpr( 1737 newLogRange(&PipelineExpr{ 1738 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "namespace", Value: "tns"}}), 1739 MultiStages: MultiStageExpr{ 1740 newLineFilterExpr(labels.MatchEqual, "", "level=error"), 1741 newLabelParserExpr(OpParserTypeJSON, ""), 1742 &LabelFilterExpr{ 1743 LabelFilterer: log.NewAndLabelFilter( 1744 log.NewNumericLabelFilter(log.LabelFilterGreaterThanOrEqual, "foo", 5), 1745 log.NewDurationLabelFilter(log.LabelFilterLesserThan, "bar", 25*time.Millisecond), 1746 ), 1747 }, 1748 }, 1749 }, 1750 5*time.Minute, 1751 newUnwrapExpr("latency", ""), 1752 nil), 1753 OpRangeTypeSum, nil, nil, 1754 ), 1755 }, 1756 { 1757 in: `sum_over_time({namespace="tns"} |= "level=error" | json |foo==5,bar<25ms| unwrap latency [5m])`, 1758 exp: newRangeAggregationExpr( 1759 newLogRange(&PipelineExpr{ 1760 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "namespace", Value: "tns"}}), 1761 MultiStages: MultiStageExpr{ 1762 newLineFilterExpr(labels.MatchEqual, "", "level=error"), 1763 newLabelParserExpr(OpParserTypeJSON, ""), 1764 &LabelFilterExpr{ 1765 LabelFilterer: log.NewAndLabelFilter( 1766 log.NewNumericLabelFilter(log.LabelFilterEqual, "foo", 5), 1767 log.NewDurationLabelFilter(log.LabelFilterLesserThan, "bar", 25*time.Millisecond), 1768 ), 1769 }, 1770 }, 1771 }, 1772 5*time.Minute, 1773 newUnwrapExpr("latency", ""), 1774 nil), 1775 OpRangeTypeSum, nil, nil, 1776 ), 1777 }, 1778 { 1779 in: `stddev_over_time({app="foo"} |= "bar" | unwrap bar [5m])`, 1780 exp: newRangeAggregationExpr( 1781 newLogRange(&PipelineExpr{ 1782 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1783 MultiStages: MultiStageExpr{ 1784 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1785 }, 1786 }, 1787 5*time.Minute, 1788 newUnwrapExpr("bar", ""), 1789 nil), 1790 OpRangeTypeStddev, nil, nil, 1791 ), 1792 }, 1793 { 1794 in: `min_over_time({app="foo"} | unwrap bar [5m])`, 1795 exp: newRangeAggregationExpr( 1796 newLogRange( 1797 newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1798 5*time.Minute, 1799 newUnwrapExpr("bar", ""), 1800 nil), 1801 OpRangeTypeMin, nil, nil, 1802 ), 1803 }, 1804 { 1805 in: `min_over_time({app="foo"} | unwrap bar [5m]) by ()`, 1806 exp: newRangeAggregationExpr( 1807 newLogRange( 1808 newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1809 5*time.Minute, 1810 newUnwrapExpr("bar", ""), 1811 nil), 1812 OpRangeTypeMin, &Grouping{}, nil, 1813 ), 1814 }, 1815 { 1816 in: `max_over_time({app="foo"} | unwrap bar [5m]) without ()`, 1817 exp: newRangeAggregationExpr( 1818 newLogRange( 1819 newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1820 5*time.Minute, 1821 newUnwrapExpr("bar", ""), 1822 nil), 1823 OpRangeTypeMax, &Grouping{Without: true}, nil, 1824 ), 1825 }, 1826 { 1827 in: `max_over_time({app="foo"} | unwrap bar [5m]) without (foo,bar)`, 1828 exp: newRangeAggregationExpr( 1829 newLogRange( 1830 newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1831 5*time.Minute, 1832 newUnwrapExpr("bar", ""), 1833 nil), 1834 OpRangeTypeMax, &Grouping{Without: true, Groups: []string{"foo", "bar"}}, nil, 1835 ), 1836 }, 1837 { 1838 in: `max_over_time({app="foo"} | unwrap bar [5m] offset 5m) without (foo,bar)`, 1839 exp: newRangeAggregationExpr( 1840 newLogRange( 1841 newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1842 5*time.Minute, 1843 newUnwrapExpr("bar", ""), 1844 newOffsetExpr(5*time.Minute)), 1845 OpRangeTypeMax, &Grouping{Without: true, Groups: []string{"foo", "bar"}}, nil, 1846 ), 1847 }, 1848 { 1849 in: `max_over_time(({app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1850 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo )[5m])`, 1851 exp: newRangeAggregationExpr( 1852 newLogRange(&PipelineExpr{ 1853 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1854 MultiStages: MultiStageExpr{ 1855 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1856 newLabelParserExpr(OpParserTypeJSON, ""), 1857 &LabelFilterExpr{ 1858 LabelFilterer: log.NewOrLabelFilter( 1859 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1860 log.NewAndLabelFilter( 1861 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1862 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1863 ), 1864 ), 1865 }, 1866 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 1867 newLabelFmtExpr([]log.LabelFmt{ 1868 log.NewRenameLabelFmt("foo", "bar"), 1869 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 1870 }), 1871 }, 1872 }, 1873 5*time.Minute, 1874 newUnwrapExpr("foo", ""), 1875 nil), 1876 OpRangeTypeMax, nil, nil, 1877 ), 1878 }, 1879 { 1880 in: `quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1881 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m])`, 1882 exp: newRangeAggregationExpr( 1883 newLogRange(&PipelineExpr{ 1884 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1885 MultiStages: MultiStageExpr{ 1886 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1887 newLabelParserExpr(OpParserTypeJSON, ""), 1888 &LabelFilterExpr{ 1889 LabelFilterer: log.NewOrLabelFilter( 1890 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1891 log.NewAndLabelFilter( 1892 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1893 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1894 ), 1895 ), 1896 }, 1897 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 1898 newLabelFmtExpr([]log.LabelFmt{ 1899 log.NewRenameLabelFmt("foo", "bar"), 1900 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 1901 }), 1902 }, 1903 }, 1904 5*time.Minute, 1905 newUnwrapExpr("foo", ""), 1906 nil), 1907 OpRangeTypeQuantile, nil, NewStringLabelFilter("0.99998"), 1908 ), 1909 }, 1910 { 1911 in: `quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1912 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m]) by (namespace,instance)`, 1913 exp: newRangeAggregationExpr( 1914 newLogRange(&PipelineExpr{ 1915 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1916 MultiStages: MultiStageExpr{ 1917 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1918 newLabelParserExpr(OpParserTypeJSON, ""), 1919 &LabelFilterExpr{ 1920 LabelFilterer: log.NewOrLabelFilter( 1921 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1922 log.NewAndLabelFilter( 1923 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1924 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1925 ), 1926 ), 1927 }, 1928 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 1929 newLabelFmtExpr([]log.LabelFmt{ 1930 log.NewRenameLabelFmt("foo", "bar"), 1931 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 1932 }), 1933 }, 1934 }, 1935 5*time.Minute, 1936 newUnwrapExpr("foo", ""), 1937 nil), 1938 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 1939 ), 1940 }, 1941 { 1942 in: `quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1943 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo | __error__ !~".+"[5m]) by (namespace,instance)`, 1944 exp: newRangeAggregationExpr( 1945 newLogRange(&PipelineExpr{ 1946 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1947 MultiStages: MultiStageExpr{ 1948 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1949 newLabelParserExpr(OpParserTypeJSON, ""), 1950 &LabelFilterExpr{ 1951 LabelFilterer: log.NewOrLabelFilter( 1952 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1953 log.NewAndLabelFilter( 1954 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1955 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1956 ), 1957 ), 1958 }, 1959 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 1960 newLabelFmtExpr([]log.LabelFmt{ 1961 log.NewRenameLabelFmt("foo", "bar"), 1962 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 1963 }), 1964 }, 1965 }, 1966 5*time.Minute, 1967 newUnwrapExpr("foo", "").addPostFilter(log.NewStringLabelFilter(mustNewMatcher(labels.MatchNotRegexp, logqlmodel.ErrorLabel, ".+"))), 1968 nil), 1969 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 1970 ), 1971 }, 1972 { 1973 in: `sum without (foo) ( 1974 quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 1975 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 1976 ) by (namespace,instance) 1977 )`, 1978 exp: mustNewVectorAggregationExpr( 1979 newRangeAggregationExpr( 1980 newLogRange(&PipelineExpr{ 1981 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 1982 MultiStages: MultiStageExpr{ 1983 newLineFilterExpr(labels.MatchEqual, "", "bar"), 1984 newLabelParserExpr(OpParserTypeJSON, ""), 1985 &LabelFilterExpr{ 1986 LabelFilterer: log.NewOrLabelFilter( 1987 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 1988 log.NewAndLabelFilter( 1989 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 1990 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 1991 ), 1992 ), 1993 }, 1994 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 1995 newLabelFmtExpr([]log.LabelFmt{ 1996 log.NewRenameLabelFmt("foo", "bar"), 1997 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 1998 }), 1999 }, 2000 }, 2001 5*time.Minute, 2002 newUnwrapExpr("foo", ""), 2003 nil), 2004 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 2005 ), 2006 OpTypeSum, 2007 &Grouping{Without: true, Groups: []string{"foo"}}, 2008 nil, 2009 ), 2010 }, 2011 { 2012 in: `sum without (foo) ( 2013 quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2014 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] offset 5m 2015 ) by (namespace,instance) 2016 )`, 2017 exp: mustNewVectorAggregationExpr( 2018 newRangeAggregationExpr( 2019 newLogRange(&PipelineExpr{ 2020 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2021 MultiStages: MultiStageExpr{ 2022 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2023 newLabelParserExpr(OpParserTypeJSON, ""), 2024 &LabelFilterExpr{ 2025 LabelFilterer: log.NewOrLabelFilter( 2026 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2027 log.NewAndLabelFilter( 2028 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2029 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2030 ), 2031 ), 2032 }, 2033 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2034 newLabelFmtExpr([]log.LabelFmt{ 2035 log.NewRenameLabelFmt("foo", "bar"), 2036 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2037 }), 2038 }, 2039 }, 2040 5*time.Minute, 2041 newUnwrapExpr("foo", ""), 2042 newOffsetExpr(5*time.Minute)), 2043 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 2044 ), 2045 OpTypeSum, 2046 &Grouping{Without: true, Groups: []string{"foo"}}, 2047 nil, 2048 ), 2049 }, 2050 { 2051 in: `sum without (foo) ( 2052 quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2053 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap duration(foo) [5m] 2054 ) by (namespace,instance) 2055 )`, 2056 exp: mustNewVectorAggregationExpr( 2057 newRangeAggregationExpr( 2058 newLogRange(&PipelineExpr{ 2059 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2060 MultiStages: MultiStageExpr{ 2061 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2062 newLabelParserExpr(OpParserTypeJSON, ""), 2063 &LabelFilterExpr{ 2064 LabelFilterer: log.NewOrLabelFilter( 2065 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2066 log.NewAndLabelFilter( 2067 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2068 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2069 ), 2070 ), 2071 }, 2072 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2073 newLabelFmtExpr([]log.LabelFmt{ 2074 log.NewRenameLabelFmt("foo", "bar"), 2075 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2076 }), 2077 }, 2078 }, 2079 5*time.Minute, 2080 newUnwrapExpr("foo", OpConvDuration), 2081 nil), 2082 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 2083 ), 2084 OpTypeSum, 2085 &Grouping{Without: true, Groups: []string{"foo"}}, 2086 nil, 2087 ), 2088 }, 2089 { 2090 in: `sum without (foo) ( 2091 quantile_over_time(.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2092 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap duration(foo) [5m] 2093 ) by (namespace,instance) 2094 )`, 2095 exp: mustNewVectorAggregationExpr( 2096 newRangeAggregationExpr( 2097 newLogRange(&PipelineExpr{ 2098 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2099 MultiStages: MultiStageExpr{ 2100 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2101 newLabelParserExpr(OpParserTypeJSON, ""), 2102 &LabelFilterExpr{ 2103 LabelFilterer: log.NewOrLabelFilter( 2104 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2105 log.NewAndLabelFilter( 2106 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2107 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2108 ), 2109 ), 2110 }, 2111 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2112 newLabelFmtExpr([]log.LabelFmt{ 2113 log.NewRenameLabelFmt("foo", "bar"), 2114 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2115 }), 2116 }, 2117 }, 2118 5*time.Minute, 2119 newUnwrapExpr("foo", OpConvDuration), 2120 nil), 2121 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter(".99998"), 2122 ), 2123 OpTypeSum, 2124 &Grouping{Without: true, Groups: []string{"foo"}}, 2125 nil, 2126 ), 2127 }, 2128 { 2129 in: `sum without (foo) ( 2130 quantile_over_time(.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2131 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap duration_seconds(foo) [5m] 2132 ) by (namespace,instance) 2133 )`, 2134 exp: mustNewVectorAggregationExpr( 2135 newRangeAggregationExpr( 2136 newLogRange(&PipelineExpr{ 2137 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2138 MultiStages: MultiStageExpr{ 2139 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2140 newLabelParserExpr(OpParserTypeJSON, ""), 2141 &LabelFilterExpr{ 2142 LabelFilterer: log.NewOrLabelFilter( 2143 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2144 log.NewAndLabelFilter( 2145 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2146 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2147 ), 2148 ), 2149 }, 2150 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2151 newLabelFmtExpr([]log.LabelFmt{ 2152 log.NewRenameLabelFmt("foo", "bar"), 2153 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2154 }), 2155 }, 2156 }, 2157 5*time.Minute, 2158 newUnwrapExpr("foo", OpConvDurationSeconds), 2159 nil), 2160 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter(".99998"), 2161 ), 2162 OpTypeSum, 2163 &Grouping{Without: true, Groups: []string{"foo"}}, 2164 nil, 2165 ), 2166 }, 2167 { 2168 in: `topk(10, 2169 quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2170 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2171 ) by (namespace,instance) 2172 )`, 2173 exp: mustNewVectorAggregationExpr( 2174 newRangeAggregationExpr( 2175 newLogRange(&PipelineExpr{ 2176 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2177 MultiStages: MultiStageExpr{ 2178 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2179 newLabelParserExpr(OpParserTypeJSON, ""), 2180 &LabelFilterExpr{ 2181 LabelFilterer: log.NewOrLabelFilter( 2182 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2183 log.NewAndLabelFilter( 2184 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2185 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2186 ), 2187 ), 2188 }, 2189 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2190 newLabelFmtExpr([]log.LabelFmt{ 2191 log.NewRenameLabelFmt("foo", "bar"), 2192 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2193 }), 2194 }, 2195 }, 2196 5*time.Minute, 2197 newUnwrapExpr("foo", ""), 2198 nil), 2199 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 2200 ), 2201 OpTypeTopK, 2202 nil, 2203 NewStringLabelFilter("10"), 2204 ), 2205 }, 2206 { 2207 in: ` 2208 sum by (foo,bar) ( 2209 quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2210 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2211 ) by (namespace,instance) 2212 ) 2213 + 2214 avg( 2215 avg_over_time({app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2216 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2217 ) by (namespace,instance) 2218 ) by (foo,bar) 2219 `, 2220 exp: mustNewBinOpExpr(OpTypeAdd, &BinOpOptions{ 2221 VectorMatching: &VectorMatching{Card: CardOneToOne}, ReturnBool: false, 2222 }, 2223 mustNewVectorAggregationExpr( 2224 newRangeAggregationExpr( 2225 newLogRange(&PipelineExpr{ 2226 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2227 MultiStages: MultiStageExpr{ 2228 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2229 newLabelParserExpr(OpParserTypeJSON, ""), 2230 &LabelFilterExpr{ 2231 LabelFilterer: log.NewOrLabelFilter( 2232 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2233 log.NewAndLabelFilter( 2234 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2235 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2236 ), 2237 ), 2238 }, 2239 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2240 newLabelFmtExpr([]log.LabelFmt{ 2241 log.NewRenameLabelFmt("foo", "bar"), 2242 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2243 }), 2244 }, 2245 }, 2246 5*time.Minute, 2247 newUnwrapExpr("foo", ""), 2248 nil), 2249 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 2250 ), 2251 OpTypeSum, 2252 &Grouping{Groups: []string{"foo", "bar"}}, 2253 nil, 2254 ), 2255 mustNewVectorAggregationExpr( 2256 newRangeAggregationExpr( 2257 newLogRange(&PipelineExpr{ 2258 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2259 MultiStages: MultiStageExpr{ 2260 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2261 newLabelParserExpr(OpParserTypeJSON, ""), 2262 &LabelFilterExpr{ 2263 LabelFilterer: log.NewOrLabelFilter( 2264 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2265 log.NewAndLabelFilter( 2266 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2267 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2268 ), 2269 ), 2270 }, 2271 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2272 newLabelFmtExpr([]log.LabelFmt{ 2273 log.NewRenameLabelFmt("foo", "bar"), 2274 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2275 }), 2276 }, 2277 }, 2278 5*time.Minute, 2279 newUnwrapExpr("foo", ""), 2280 nil), 2281 OpRangeTypeAvg, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, nil, 2282 ), 2283 OpTypeAvg, 2284 &Grouping{Groups: []string{"foo", "bar"}}, 2285 nil, 2286 ), 2287 ), 2288 }, 2289 { 2290 in: ` 2291 sum by (foo,bar) ( 2292 quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2293 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2294 ) by (namespace,instance) 2295 ) 2296 + ignoring (bar) 2297 avg( 2298 avg_over_time({app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2299 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2300 ) by (namespace,instance) 2301 ) by (foo) 2302 `, 2303 exp: mustNewBinOpExpr(OpTypeAdd, &BinOpOptions{ReturnBool: false, VectorMatching: &VectorMatching{Card: CardOneToOne, On: false, MatchingLabels: []string{"bar"}}}, 2304 mustNewVectorAggregationExpr( 2305 newRangeAggregationExpr( 2306 newLogRange(&PipelineExpr{ 2307 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2308 MultiStages: MultiStageExpr{ 2309 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2310 newLabelParserExpr(OpParserTypeJSON, ""), 2311 &LabelFilterExpr{ 2312 LabelFilterer: log.NewOrLabelFilter( 2313 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2314 log.NewAndLabelFilter( 2315 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2316 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2317 ), 2318 ), 2319 }, 2320 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2321 newLabelFmtExpr([]log.LabelFmt{ 2322 log.NewRenameLabelFmt("foo", "bar"), 2323 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2324 }), 2325 }, 2326 }, 2327 5*time.Minute, 2328 newUnwrapExpr("foo", ""), 2329 nil), 2330 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 2331 ), 2332 OpTypeSum, 2333 &Grouping{Groups: []string{"foo", "bar"}}, 2334 nil, 2335 ), 2336 mustNewVectorAggregationExpr( 2337 newRangeAggregationExpr( 2338 newLogRange(&PipelineExpr{ 2339 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2340 MultiStages: MultiStageExpr{ 2341 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2342 newLabelParserExpr(OpParserTypeJSON, ""), 2343 &LabelFilterExpr{ 2344 LabelFilterer: log.NewOrLabelFilter( 2345 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2346 log.NewAndLabelFilter( 2347 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2348 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2349 ), 2350 ), 2351 }, 2352 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2353 newLabelFmtExpr([]log.LabelFmt{ 2354 log.NewRenameLabelFmt("foo", "bar"), 2355 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2356 }), 2357 }, 2358 }, 2359 5*time.Minute, 2360 newUnwrapExpr("foo", ""), 2361 nil), 2362 OpRangeTypeAvg, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, nil, 2363 ), 2364 OpTypeAvg, 2365 &Grouping{Groups: []string{"foo"}}, 2366 nil, 2367 ), 2368 ), 2369 }, 2370 { 2371 in: ` 2372 sum by (foo,bar) ( 2373 quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2374 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2375 ) by (namespace,instance) 2376 ) 2377 + on (foo) 2378 avg( 2379 avg_over_time({app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2380 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2381 ) by (namespace,instance) 2382 ) by (foo) 2383 `, 2384 exp: mustNewBinOpExpr(OpTypeAdd, &BinOpOptions{ReturnBool: false, VectorMatching: &VectorMatching{Card: CardOneToOne, On: true, MatchingLabels: []string{"foo"}}}, 2385 mustNewVectorAggregationExpr( 2386 newRangeAggregationExpr( 2387 newLogRange(&PipelineExpr{ 2388 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2389 MultiStages: MultiStageExpr{ 2390 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2391 newLabelParserExpr(OpParserTypeJSON, ""), 2392 &LabelFilterExpr{ 2393 LabelFilterer: log.NewOrLabelFilter( 2394 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2395 log.NewAndLabelFilter( 2396 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2397 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2398 ), 2399 ), 2400 }, 2401 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2402 newLabelFmtExpr([]log.LabelFmt{ 2403 log.NewRenameLabelFmt("foo", "bar"), 2404 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2405 }), 2406 }, 2407 }, 2408 5*time.Minute, 2409 newUnwrapExpr("foo", ""), 2410 nil), 2411 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 2412 ), 2413 OpTypeSum, 2414 &Grouping{Groups: []string{"foo", "bar"}}, 2415 nil, 2416 ), 2417 mustNewVectorAggregationExpr( 2418 newRangeAggregationExpr( 2419 newLogRange(&PipelineExpr{ 2420 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2421 MultiStages: MultiStageExpr{ 2422 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2423 newLabelParserExpr(OpParserTypeJSON, ""), 2424 &LabelFilterExpr{ 2425 LabelFilterer: log.NewOrLabelFilter( 2426 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2427 log.NewAndLabelFilter( 2428 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2429 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2430 ), 2431 ), 2432 }, 2433 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2434 newLabelFmtExpr([]log.LabelFmt{ 2435 log.NewRenameLabelFmt("foo", "bar"), 2436 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2437 }), 2438 }, 2439 }, 2440 5*time.Minute, 2441 newUnwrapExpr("foo", ""), 2442 nil), 2443 OpRangeTypeAvg, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, nil, 2444 ), 2445 OpTypeAvg, 2446 &Grouping{Groups: []string{"foo"}}, 2447 nil, 2448 ), 2449 ), 2450 }, 2451 { 2452 in: ` 2453 sum by (foo,bar) ( 2454 quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2455 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2456 ) by (namespace,instance) 2457 ) 2458 + ignoring (bar) group_left (foo) 2459 avg( 2460 avg_over_time({app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2461 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2462 ) by (namespace,instance) 2463 ) by (foo) 2464 `, 2465 exp: mustNewBinOpExpr(OpTypeAdd, &BinOpOptions{ReturnBool: false, VectorMatching: &VectorMatching{Card: CardManyToOne, Include: []string{"foo"}, On: false, MatchingLabels: []string{"bar"}}}, 2466 mustNewVectorAggregationExpr( 2467 newRangeAggregationExpr( 2468 newLogRange(&PipelineExpr{ 2469 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2470 MultiStages: MultiStageExpr{ 2471 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2472 newLabelParserExpr(OpParserTypeJSON, ""), 2473 &LabelFilterExpr{ 2474 LabelFilterer: log.NewOrLabelFilter( 2475 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2476 log.NewAndLabelFilter( 2477 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2478 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2479 ), 2480 ), 2481 }, 2482 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2483 newLabelFmtExpr([]log.LabelFmt{ 2484 log.NewRenameLabelFmt("foo", "bar"), 2485 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2486 }), 2487 }, 2488 }, 2489 5*time.Minute, 2490 newUnwrapExpr("foo", ""), 2491 nil), 2492 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 2493 ), 2494 OpTypeSum, 2495 &Grouping{Groups: []string{"foo", "bar"}}, 2496 nil, 2497 ), 2498 mustNewVectorAggregationExpr( 2499 newRangeAggregationExpr( 2500 newLogRange(&PipelineExpr{ 2501 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2502 MultiStages: MultiStageExpr{ 2503 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2504 newLabelParserExpr(OpParserTypeJSON, ""), 2505 &LabelFilterExpr{ 2506 LabelFilterer: log.NewOrLabelFilter( 2507 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2508 log.NewAndLabelFilter( 2509 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2510 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2511 ), 2512 ), 2513 }, 2514 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2515 newLabelFmtExpr([]log.LabelFmt{ 2516 log.NewRenameLabelFmt("foo", "bar"), 2517 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2518 }), 2519 }, 2520 }, 2521 5*time.Minute, 2522 newUnwrapExpr("foo", ""), 2523 nil), 2524 OpRangeTypeAvg, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, nil, 2525 ), 2526 OpTypeAvg, 2527 &Grouping{Groups: []string{"foo"}}, 2528 nil, 2529 ), 2530 ), 2531 }, 2532 { 2533 in: ` 2534 sum by (app,machine) (count_over_time({app="foo"}[1m])) > bool on () group_right (app) sum by (app) (count_over_time({app="foo"}[1m])) 2535 `, 2536 exp: mustNewBinOpExpr(OpTypeGT, &BinOpOptions{ReturnBool: true, VectorMatching: &VectorMatching{Card: CardOneToMany, Include: []string{"app"}, On: true, MatchingLabels: nil}}, 2537 mustNewVectorAggregationExpr( 2538 newRangeAggregationExpr( 2539 &LogRange{ 2540 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2541 Interval: 1 * time.Minute, 2542 }, 2543 OpRangeTypeCount, nil, nil, 2544 ), 2545 OpTypeSum, 2546 &Grouping{Groups: []string{"app", "machine"}}, 2547 nil, 2548 ), 2549 mustNewVectorAggregationExpr( 2550 newRangeAggregationExpr( 2551 &LogRange{ 2552 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2553 Interval: 1 * time.Minute, 2554 }, 2555 OpRangeTypeCount, nil, nil, 2556 ), 2557 OpTypeSum, 2558 &Grouping{Groups: []string{"app"}}, 2559 nil, 2560 ), 2561 ), 2562 }, 2563 { 2564 in: ` 2565 sum by (app,machine) (count_over_time({app="foo"}[1m])) > bool on () group_right sum by (app) (count_over_time({app="foo"}[1m])) 2566 `, 2567 exp: mustNewBinOpExpr(OpTypeGT, &BinOpOptions{ReturnBool: true, VectorMatching: &VectorMatching{Card: CardOneToMany, Include: nil, On: true, MatchingLabels: nil}}, 2568 mustNewVectorAggregationExpr( 2569 newRangeAggregationExpr( 2570 &LogRange{ 2571 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2572 Interval: 1 * time.Minute, 2573 }, 2574 OpRangeTypeCount, nil, nil, 2575 ), 2576 OpTypeSum, 2577 &Grouping{Groups: []string{"app", "machine"}}, 2578 nil, 2579 ), 2580 mustNewVectorAggregationExpr( 2581 newRangeAggregationExpr( 2582 &LogRange{ 2583 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2584 Interval: 1 * time.Minute, 2585 }, 2586 OpRangeTypeCount, nil, nil, 2587 ), 2588 OpTypeSum, 2589 &Grouping{Groups: []string{"app"}}, 2590 nil, 2591 ), 2592 ), 2593 }, 2594 { 2595 in: ` 2596 label_replace( 2597 sum by (foo,bar) ( 2598 quantile_over_time(0.99998,{app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2599 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2600 ) by (namespace,instance) 2601 ) 2602 + 2603 avg( 2604 avg_over_time({app="foo"} |= "bar" | json | latency >= 250ms or ( status_code < 500 and status_code > 200) 2605 | line_format "blip{{ .foo }}blop {{.status_code}}" | label_format foo=bar,status_code="buzz{{.bar}}" | unwrap foo [5m] 2606 ) by (namespace,instance) 2607 ) by (foo,bar), 2608 "foo", 2609 "$1", 2610 "svc", 2611 "(.*)" 2612 )`, 2613 exp: mustNewLabelReplaceExpr( 2614 mustNewBinOpExpr(OpTypeAdd, &BinOpOptions{VectorMatching: &VectorMatching{Card: CardOneToOne}, ReturnBool: false}, 2615 mustNewVectorAggregationExpr( 2616 newRangeAggregationExpr( 2617 newLogRange(&PipelineExpr{ 2618 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2619 MultiStages: MultiStageExpr{ 2620 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2621 newLabelParserExpr(OpParserTypeJSON, ""), 2622 &LabelFilterExpr{ 2623 LabelFilterer: log.NewOrLabelFilter( 2624 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2625 log.NewAndLabelFilter( 2626 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2627 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2628 ), 2629 ), 2630 }, 2631 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2632 newLabelFmtExpr([]log.LabelFmt{ 2633 log.NewRenameLabelFmt("foo", "bar"), 2634 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2635 }), 2636 }, 2637 }, 2638 5*time.Minute, 2639 newUnwrapExpr("foo", ""), 2640 nil), 2641 OpRangeTypeQuantile, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, NewStringLabelFilter("0.99998"), 2642 ), 2643 OpTypeSum, 2644 &Grouping{Groups: []string{"foo", "bar"}}, 2645 nil, 2646 ), 2647 mustNewVectorAggregationExpr( 2648 newRangeAggregationExpr( 2649 newLogRange(&PipelineExpr{ 2650 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2651 MultiStages: MultiStageExpr{ 2652 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2653 newLabelParserExpr(OpParserTypeJSON, ""), 2654 &LabelFilterExpr{ 2655 LabelFilterer: log.NewOrLabelFilter( 2656 log.NewDurationLabelFilter(log.LabelFilterGreaterThanOrEqual, "latency", 250*time.Millisecond), 2657 log.NewAndLabelFilter( 2658 log.NewNumericLabelFilter(log.LabelFilterLesserThan, "status_code", 500.0), 2659 log.NewNumericLabelFilter(log.LabelFilterGreaterThan, "status_code", 200.0), 2660 ), 2661 ), 2662 }, 2663 newLineFmtExpr("blip{{ .foo }}blop {{.status_code}}"), 2664 newLabelFmtExpr([]log.LabelFmt{ 2665 log.NewRenameLabelFmt("foo", "bar"), 2666 log.NewTemplateLabelFmt("status_code", "buzz{{.bar}}"), 2667 }), 2668 }, 2669 }, 2670 5*time.Minute, 2671 newUnwrapExpr("foo", ""), 2672 nil), 2673 OpRangeTypeAvg, &Grouping{Without: false, Groups: []string{"namespace", "instance"}}, nil, 2674 ), 2675 OpTypeAvg, 2676 &Grouping{Groups: []string{"foo", "bar"}}, 2677 nil, 2678 ), 2679 ), 2680 "foo", "$1", "svc", "(.*)", 2681 ), 2682 }, 2683 { 2684 // ensure binary ops with two literals are reduced recursively 2685 in: `1 + 1 + 1`, 2686 exp: &LiteralExpr{Val: 3}, 2687 }, 2688 { 2689 // ensure binary ops with two literals are reduced when comparisons are used 2690 in: `1 == 1`, 2691 exp: &LiteralExpr{Val: 1}, 2692 }, 2693 { 2694 // ensure binary ops with two literals are reduced when comparisons are used 2695 in: `1 != 1`, 2696 exp: &LiteralExpr{Val: 0}, 2697 }, 2698 { 2699 // ensure binary ops with two literals are reduced when comparisons are used 2700 in: `1 > 1`, 2701 exp: &LiteralExpr{Val: 0}, 2702 }, 2703 { 2704 // ensure binary ops with two literals are reduced when comparisons are used 2705 in: `1 >= 1`, 2706 exp: &LiteralExpr{Val: 1}, 2707 }, 2708 { 2709 // ensure binary ops with two literals are reduced when comparisons are used 2710 in: `1 < 1`, 2711 exp: &LiteralExpr{Val: 0}, 2712 }, 2713 { 2714 // ensure binary ops with two literals are reduced when comparisons are used 2715 in: `1 <= 1`, 2716 exp: &LiteralExpr{Val: 1}, 2717 }, 2718 { 2719 // ensure binary ops with two literals are reduced recursively when comparisons are used 2720 in: `1 >= 1 > 1`, 2721 exp: &LiteralExpr{Val: 0}, 2722 }, 2723 { 2724 in: `{foo="bar"} + {foo="bar"}`, 2725 err: logqlmodel.NewParseError(`unexpected type for left leg of binary operation (+): *syntax.MatchersExpr`, 0, 0), 2726 }, 2727 { 2728 in: `sum(count_over_time({foo="bar"}[5m])) by (foo) - {foo="bar"}`, 2729 err: logqlmodel.NewParseError(`unexpected type for right leg of binary operation (-): *syntax.MatchersExpr`, 0, 0), 2730 }, 2731 { 2732 in: `{foo="bar"} / sum(count_over_time({foo="bar"}[5m])) by (foo)`, 2733 err: logqlmodel.NewParseError(`unexpected type for left leg of binary operation (/): *syntax.MatchersExpr`, 0, 0), 2734 }, 2735 { 2736 in: `sum(count_over_time({foo="bar"}[5m])) by (foo) or 1`, 2737 err: logqlmodel.NewParseError(`unexpected literal for right leg of logical/set binary operation (or): 1.000000`, 0, 0), 2738 }, 2739 { 2740 in: `1 unless sum(count_over_time({foo="bar"}[5m])) by (foo)`, 2741 err: logqlmodel.NewParseError(`unexpected literal for left leg of logical/set binary operation (unless): 1.000000`, 0, 0), 2742 }, 2743 { 2744 in: `sum(count_over_time({foo="bar"}[5m])) by (foo) + 1 or 1`, 2745 err: logqlmodel.NewParseError(`unexpected literal for right leg of logical/set binary operation (or): 1.000000`, 0, 0), 2746 }, 2747 { 2748 in: `count_over_time({ foo ="bar" }[12m]) > count_over_time({ foo = "bar" }[12m])`, 2749 exp: &BinOpExpr{ 2750 Op: OpTypeGT, 2751 Opts: &BinOpOptions{ 2752 ReturnBool: false, 2753 VectorMatching: &VectorMatching{Card: CardOneToOne}, 2754 }, 2755 SampleExpr: &RangeAggregationExpr{ 2756 Left: &LogRange{ 2757 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 2758 Interval: 12 * time.Minute, 2759 }, 2760 Operation: "count_over_time", 2761 }, 2762 RHS: &RangeAggregationExpr{ 2763 Left: &LogRange{ 2764 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 2765 Interval: 12 * time.Minute, 2766 }, 2767 Operation: "count_over_time", 2768 }, 2769 }, 2770 }, 2771 { 2772 in: `count_over_time({ foo = "bar" }[12m]) > 1`, 2773 exp: &BinOpExpr{ 2774 Op: OpTypeGT, 2775 Opts: &BinOpOptions{ 2776 ReturnBool: false, 2777 VectorMatching: &VectorMatching{Card: CardOneToOne}, 2778 }, 2779 SampleExpr: &RangeAggregationExpr{ 2780 Left: &LogRange{ 2781 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 2782 Interval: 12 * time.Minute, 2783 }, 2784 Operation: "count_over_time", 2785 }, 2786 RHS: &LiteralExpr{Val: 1}, 2787 }, 2788 }, 2789 { 2790 // cannot compare metric & log queries 2791 in: `count_over_time({ foo = "bar" }[12m]) > { foo = "bar" }`, 2792 err: logqlmodel.NewParseError("unexpected type for right leg of binary operation (>): *syntax.MatchersExpr", 0, 0), 2793 }, 2794 { 2795 in: `count_over_time({ foo = "bar" }[12m]) or count_over_time({ foo = "bar" }[12m]) > 1`, 2796 exp: &BinOpExpr{ 2797 Op: OpTypeOr, 2798 Opts: &BinOpOptions{ 2799 ReturnBool: false, 2800 VectorMatching: &VectorMatching{}, 2801 }, 2802 SampleExpr: &RangeAggregationExpr{ 2803 Left: &LogRange{ 2804 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 2805 Interval: 12 * time.Minute, 2806 }, 2807 Operation: "count_over_time", 2808 }, 2809 RHS: &BinOpExpr{ 2810 Op: OpTypeGT, 2811 Opts: &BinOpOptions{ 2812 ReturnBool: false, 2813 VectorMatching: &VectorMatching{Card: CardOneToOne}, 2814 }, 2815 SampleExpr: &RangeAggregationExpr{ 2816 Left: &LogRange{ 2817 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 2818 Interval: 12 * time.Minute, 2819 }, 2820 Operation: "count_over_time", 2821 }, 2822 RHS: &LiteralExpr{Val: 1}, 2823 }, 2824 }, 2825 }, 2826 { 2827 // test associativity 2828 in: `1 > 1 < 1`, 2829 exp: &LiteralExpr{Val: 1}, 2830 }, 2831 { 2832 // bool modifiers are reduced-away between two literal legs 2833 in: `1 > 1 > bool 1`, 2834 exp: &LiteralExpr{Val: 0}, 2835 }, 2836 { 2837 // cannot lead with bool modifier 2838 in: `bool 1 > 1 > bool 1`, 2839 err: logqlmodel.NewParseError("syntax error: unexpected bool", 1, 1), 2840 }, 2841 { 2842 in: `sum_over_time({namespace="tns"} |= "level=error" | json |foo>=5,bar<25ms| unwrap latency [5m]) by (foo)`, 2843 err: logqlmodel.NewParseError("grouping not allowed for sum_over_time aggregation", 0, 0), 2844 }, 2845 { 2846 in: `sum_over_time(50,{namespace="tns"} |= "level=error" | json |foo>=5,bar<25ms| unwrap latency [5m])`, 2847 err: logqlmodel.NewParseError("parameter 50 not supported for operation sum_over_time", 0, 0), 2848 }, 2849 { 2850 in: `quantile_over_time({namespace="tns"} |= "level=error" | json |foo>=5,bar<25ms| unwrap latency [5m])`, 2851 err: logqlmodel.NewParseError("parameter required for operation quantile_over_time", 0, 0), 2852 }, 2853 { 2854 in: `quantile_over_time(foo,{namespace="tns"} |= "level=error" | json |foo>=5,bar<25ms| unwrap latency [5m])`, 2855 err: logqlmodel.NewParseError("syntax error: unexpected IDENTIFIER, expecting NUMBER or { or (", 1, 20), 2856 }, 2857 { 2858 in: `{app="foo"} 2859 # |= "bar" 2860 | json`, 2861 exp: &PipelineExpr{ 2862 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2863 MultiStages: MultiStageExpr{ 2864 newLabelParserExpr(OpParserTypeJSON, ""), 2865 }, 2866 }, 2867 }, 2868 { 2869 in: `{app="foo"} 2870 # 2871 |= "bar" 2872 | json`, 2873 exp: &PipelineExpr{ 2874 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2875 MultiStages: MultiStageExpr{ 2876 newLineFilterExpr(labels.MatchEqual, "", "bar"), 2877 newLabelParserExpr(OpParserTypeJSON, ""), 2878 }, 2879 }, 2880 }, 2881 { 2882 in: `{app="foo"} # |= "bar" | json`, 2883 exp: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2884 }, 2885 { 2886 in: `{app="foo"} | json #`, 2887 exp: &PipelineExpr{ 2888 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2889 MultiStages: MultiStageExpr{ 2890 newLabelParserExpr(OpParserTypeJSON, ""), 2891 }, 2892 }, 2893 }, 2894 { 2895 in: `#{app="foo"} | json`, 2896 err: logqlmodel.NewParseError("syntax error: unexpected $end", 1, 20), 2897 }, 2898 { 2899 in: `{app="#"}`, 2900 exp: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "#"}}), 2901 }, 2902 { 2903 in: `{app="foo"} |= "#"`, 2904 exp: &PipelineExpr{ 2905 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2906 MultiStages: MultiStageExpr{ 2907 newLineFilterExpr(labels.MatchEqual, "", "#"), 2908 }, 2909 }, 2910 }, 2911 { 2912 in: `{app="foo"} | bar="#"`, 2913 exp: &PipelineExpr{ 2914 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2915 MultiStages: MultiStageExpr{ 2916 &LabelFilterExpr{ 2917 LabelFilterer: log.NewStringLabelFilter(mustNewMatcher(labels.MatchEqual, "bar", "#")), 2918 }, 2919 }, 2920 }, 2921 }, 2922 { 2923 in: `{app="foo"} | json bob="top.sub[\"index\"]"`, 2924 exp: &PipelineExpr{ 2925 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2926 MultiStages: MultiStageExpr{ 2927 newJSONExpressionParser([]log.JSONExpression{ 2928 log.NewJSONExpr("bob", `top.sub["index"]`), 2929 }), 2930 }, 2931 }, 2932 }, 2933 { 2934 in: `{app="foo"} | json bob="top.params[0]"`, 2935 exp: &PipelineExpr{ 2936 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2937 MultiStages: MultiStageExpr{ 2938 newJSONExpressionParser([]log.JSONExpression{ 2939 log.NewJSONExpr("bob", `top.params[0]`), 2940 }), 2941 }, 2942 }, 2943 }, 2944 { 2945 in: `{app="foo"} | json response_code="response.code", api_key="request.headers[\"X-API-KEY\"]"`, 2946 exp: &PipelineExpr{ 2947 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2948 MultiStages: MultiStageExpr{ 2949 newJSONExpressionParser([]log.JSONExpression{ 2950 log.NewJSONExpr("response_code", `response.code`), 2951 log.NewJSONExpr("api_key", `request.headers["X-API-KEY"]`), 2952 }), 2953 }, 2954 }, 2955 }, 2956 { 2957 in: `{app="foo"} | json response_code, api_key="request.headers[\"X-API-KEY\"]", layer7_something_specific="layer7_something_specific"`, 2958 exp: &PipelineExpr{ 2959 Left: newMatcherExpr([]*labels.Matcher{{Type: labels.MatchEqual, Name: "app", Value: "foo"}}), 2960 MultiStages: MultiStageExpr{ 2961 newJSONExpressionParser([]log.JSONExpression{ 2962 log.NewJSONExpr("response_code", `response_code`), 2963 log.NewJSONExpr("api_key", `request.headers["X-API-KEY"]`), 2964 log.NewJSONExpr("layer7_something_specific", `layer7_something_specific`), 2965 }), 2966 }, 2967 }, 2968 }, 2969 { 2970 in: `count_over_time({ foo ="bar" } | json layer7_something_specific="layer7_something_specific" [12m])`, 2971 exp: &RangeAggregationExpr{ 2972 Left: &LogRange{ 2973 Left: &PipelineExpr{ 2974 MultiStages: MultiStageExpr{ 2975 newJSONExpressionParser([]log.JSONExpression{ 2976 log.NewJSONExpr("layer7_something_specific", `layer7_something_specific`), 2977 }), 2978 }, 2979 Left: &MatchersExpr{Mts: []*labels.Matcher{mustNewMatcher(labels.MatchEqual, "foo", "bar")}}, 2980 }, 2981 Interval: 12 * time.Minute, 2982 }, 2983 Operation: "count_over_time", 2984 }, 2985 }, 2986 } { 2987 t.Run(tc.in, func(t *testing.T) { 2988 ast, err := ParseExpr(tc.in) 2989 require.Equal(t, tc.err, err) 2990 require.Equal(t, tc.exp, ast) 2991 }) 2992 } 2993 } 2994 2995 func TestParseMatchers(t *testing.T) { 2996 tests := []struct { 2997 input string 2998 want []*labels.Matcher 2999 wantErr bool 3000 }{ 3001 { 3002 `{app="foo",cluster=~".+bar"}`, 3003 []*labels.Matcher{ 3004 mustNewMatcher(labels.MatchEqual, "app", "foo"), 3005 mustNewMatcher(labels.MatchRegexp, "cluster", ".+bar"), 3006 }, 3007 false, 3008 }, 3009 { 3010 `{app!="foo",cluster=~".+bar",bar!~".?boo"}`, 3011 []*labels.Matcher{ 3012 mustNewMatcher(labels.MatchNotEqual, "app", "foo"), 3013 mustNewMatcher(labels.MatchRegexp, "cluster", ".+bar"), 3014 mustNewMatcher(labels.MatchNotRegexp, "bar", ".?boo"), 3015 }, 3016 false, 3017 }, 3018 { 3019 `{app!="foo",cluster=~".+bar",bar!~".?boo"`, 3020 nil, 3021 true, 3022 }, 3023 { 3024 `{app!="foo",cluster=~".+bar",bar!~".?boo"} |= "test"`, 3025 nil, 3026 true, 3027 }, 3028 } 3029 for _, tt := range tests { 3030 t.Run(tt.input, func(t *testing.T) { 3031 got, err := ParseMatchers(tt.input) 3032 if (err != nil) != tt.wantErr { 3033 t.Errorf("ParseMatchers() error = %v, wantErr %v", err, tt.wantErr) 3034 return 3035 } 3036 if !reflect.DeepEqual(got, tt.want) { 3037 t.Errorf("ParseMatchers() = %v, want %v", got, tt.want) 3038 } 3039 }) 3040 } 3041 } 3042 3043 func TestIsParseError(t *testing.T) { 3044 tests := []struct { 3045 name string 3046 errFn func() error 3047 want bool 3048 }{ 3049 { 3050 "bad query", 3051 func() error { 3052 _, err := ParseExpr(`{foo`) 3053 return err 3054 }, 3055 true, 3056 }, 3057 { 3058 "other error", 3059 func() error { 3060 return errors.New("") 3061 }, 3062 false, 3063 }, 3064 } 3065 for _, tt := range tests { 3066 t.Run(tt.name, func(t *testing.T) { 3067 if got := errors.Is(tt.errFn(), logqlmodel.ErrParse); got != tt.want { 3068 t.Errorf("IsParseError() = %v, want %v", got, tt.want) 3069 } 3070 }) 3071 } 3072 } 3073 3074 func Test_PipelineCombined(t *testing.T) { 3075 query := `{job="cortex-ops/query-frontend"} |= "logging.go" | logfmt | line_format "{{.msg}}" | regexp "(?P<method>\\w+) (?P<path>[\\w|/]+) \\((?P<status>\\d+?)\\) (?P<duration>.*)" | (duration > 1s or status==200) and method="POST" | line_format "{{.duration}}|{{.method}}|{{.status}}"` 3076 3077 expr, err := ParseLogSelector(query, true) 3078 require.Nil(t, err) 3079 3080 p, err := expr.Pipeline() 3081 require.Nil(t, err) 3082 sp := p.ForStream(labels.Labels{}) 3083 line, lbs, matches := sp.Process(0, []byte(`level=debug ts=2020-10-02T10:10:42.092268913Z caller=logging.go:66 traceID=a9d4d8a928d8db1 msg="POST /api/prom/api/v1/query_range (200) 1.5s"`)) 3084 require.True(t, matches) 3085 require.Equal( 3086 t, 3087 labels.Labels{labels.Label{Name: "caller", Value: "logging.go:66"}, labels.Label{Name: "duration", Value: "1.5s"}, labels.Label{Name: "level", Value: "debug"}, labels.Label{Name: "method", Value: "POST"}, labels.Label{Name: "msg", Value: "POST /api/prom/api/v1/query_range (200) 1.5s"}, labels.Label{Name: "path", Value: "/api/prom/api/v1/query_range"}, labels.Label{Name: "status", Value: "200"}, labels.Label{Name: "traceID", Value: "a9d4d8a928d8db1"}, labels.Label{Name: "ts", Value: "2020-10-02T10:10:42.092268913Z"}}, 3088 lbs.Labels(), 3089 ) 3090 require.Equal(t, string([]byte(`1.5s|POST|200`)), string(line)) 3091 } 3092 3093 func Benchmark_PipelineCombined(b *testing.B) { 3094 query := `{job="cortex-ops/query-frontend"} |= "logging.go" | logfmt | line_format "{{.msg}}" | regexp "(?P<method>\\w+) (?P<path>[\\w|/]+) \\((?P<status>\\d+?)\\) (?P<duration>.*)" | (duration > 1s or status==200) and method="POST" | line_format "{{.duration}}|{{.method}}|{{.status}}"` 3095 3096 expr, err := ParseLogSelector(query, true) 3097 require.Nil(b, err) 3098 3099 p, err := expr.Pipeline() 3100 require.Nil(b, err) 3101 sp := p.ForStream(labels.Labels{}) 3102 var ( 3103 line []byte 3104 lbs log.LabelsResult 3105 matches bool 3106 ) 3107 in := []byte(`level=debug ts=2020-10-02T10:10:42.092268913Z caller=logging.go:66 traceID=a9d4d8a928d8db1 msg="POST /api/prom/api/v1/query_range (200) 1.5s"`) 3108 3109 b.ReportAllocs() 3110 b.ResetTimer() 3111 for i := 0; i < b.N; i++ { 3112 line, lbs, matches = sp.Process(0, in) 3113 } 3114 require.True(b, matches) 3115 require.Equal( 3116 b, 3117 labels.Labels{labels.Label{Name: "caller", Value: "logging.go:66"}, labels.Label{Name: "duration", Value: "1.5s"}, labels.Label{Name: "level", Value: "debug"}, labels.Label{Name: "method", Value: "POST"}, labels.Label{Name: "msg", Value: "POST /api/prom/api/v1/query_range (200) 1.5s"}, labels.Label{Name: "path", Value: "/api/prom/api/v1/query_range"}, labels.Label{Name: "status", Value: "200"}, labels.Label{Name: "traceID", Value: "a9d4d8a928d8db1"}, labels.Label{Name: "ts", Value: "2020-10-02T10:10:42.092268913Z"}}, 3118 lbs.Labels(), 3119 ) 3120 require.Equal(b, string([]byte(`1.5s|POST|200`)), string(line)) 3121 } 3122 3123 func Benchmark_MetricPipelineCombined(b *testing.B) { 3124 query := `count_over_time({job="cortex-ops/query-frontend"} |= "logging.go" | logfmt | line_format "{{.msg}}" | regexp "(?P<method>\\w+) (?P<path>[\\w|/]+) \\((?P<status>\\d+?)\\) (?P<duration>.*)" | (duration > 1s or status==200) and method="POST" | line_format "{{.duration}}|{{.method}}|{{.status}}"[1m])` 3125 3126 expr, err := ParseSampleExpr(query) 3127 require.Nil(b, err) 3128 3129 p, err := expr.Extractor() 3130 require.Nil(b, err) 3131 sp := p.ForStream(labels.Labels{}) 3132 var ( 3133 v float64 3134 lbs log.LabelsResult 3135 matches bool 3136 ) 3137 in := []byte(`level=debug ts=2020-10-02T10:10:42.092268913Z caller=logging.go:66 traceID=a9d4d8a928d8db1 msg="POST /api/prom/api/v1/query_range (200) 1.5s"`) 3138 b.ReportAllocs() 3139 b.ResetTimer() 3140 for i := 0; i < b.N; i++ { 3141 v, lbs, matches = sp.Process(0, in) 3142 } 3143 require.True(b, matches) 3144 require.Equal( 3145 b, 3146 labels.Labels{labels.Label{Name: "caller", Value: "logging.go:66"}, labels.Label{Name: "duration", Value: "1.5s"}, labels.Label{Name: "level", Value: "debug"}, labels.Label{Name: "method", Value: "POST"}, labels.Label{Name: "msg", Value: "POST /api/prom/api/v1/query_range (200) 1.5s"}, labels.Label{Name: "path", Value: "/api/prom/api/v1/query_range"}, labels.Label{Name: "status", Value: "200"}, labels.Label{Name: "traceID", Value: "a9d4d8a928d8db1"}, labels.Label{Name: "ts", Value: "2020-10-02T10:10:42.092268913Z"}}, 3147 lbs.Labels(), 3148 ) 3149 require.Equal(b, 1.0, v) 3150 } 3151 3152 var c []*labels.Matcher 3153 3154 func Benchmark_ParseMatchers(b *testing.B) { 3155 s := `{cpu="10",endpoint="https",instance="10.253.57.87:9100",job="node-exporter",mode="idle",namespace="observability",pod="node-exporter-l454v",service="node-exporter"}` 3156 var err error 3157 for n := 0; n < b.N; n++ { 3158 c, err = ParseMatchers(s) 3159 require.NoError(b, err) 3160 } 3161 } 3162 3163 var lbs labels.Labels 3164 3165 func Benchmark_CompareParseLabels(b *testing.B) { 3166 s := `{cpu="10",endpoint="https",instance="10.253.57.87:9100",job="node-exporter",mode="idle",namespace="observability",pod="node-exporter-l454v",service="node-exporter"}` 3167 var err error 3168 b.Run("logql", func(b *testing.B) { 3169 for n := 0; n < b.N; n++ { 3170 c, err = ParseMatchers(s) 3171 require.NoError(b, err) 3172 } 3173 }) 3174 b.Run("promql", func(b *testing.B) { 3175 for n := 0; n < b.N; n++ { 3176 lbs, err = ParseLabels(s) 3177 require.NoError(b, err) 3178 } 3179 }) 3180 } 3181 3182 func TestParseSampleExpr_equalityMatcher(t *testing.T) { 3183 for _, tc := range []struct { 3184 in string 3185 err error 3186 }{ 3187 { 3188 in: `count_over_time({foo="bar"}[5m])`, 3189 }, 3190 { 3191 in: `count_over_time({foo!="bar"}[5m])`, 3192 err: logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0), 3193 }, 3194 { 3195 in: `count_over_time({app="baz", foo!="bar"}[5m])`, 3196 }, 3197 { 3198 in: `count_over_time({app=~".+"}[5m])`, 3199 }, 3200 { 3201 in: `count_over_time({app=~".*"}[5m])`, 3202 err: logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0), 3203 }, 3204 { 3205 in: `count_over_time({app=~"bar|baz"}[5m])`, 3206 }, 3207 { 3208 in: `count_over_time({app!~"bar|baz"}[5m])`, 3209 err: logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0), 3210 }, 3211 { 3212 in: `1 + count_over_time({app=~".*"}[5m])`, 3213 err: logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0), 3214 }, 3215 { 3216 in: `1 + count_over_time({app=~".+"}[5m]) + count_over_time({app=~".*"}[5m])`, 3217 err: logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0), 3218 }, 3219 { 3220 in: `1 + count_over_time({app=~".+"}[5m]) + count_over_time({app=~".+"}[5m])`, 3221 }, 3222 { 3223 in: `1 + count_over_time({app=~".+"}[5m]) + count_over_time({app=~".*"}[5m]) + 1`, 3224 err: logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0), 3225 }, 3226 { 3227 in: `1 + count_over_time({app=~".+"}[5m]) + count_over_time({app=~".+"}[5m]) + 1`, 3228 }, 3229 } { 3230 t.Run(tc.in, func(t *testing.T) { 3231 _, err := ParseSampleExpr(tc.in) 3232 require.Equal(t, tc.err, err) 3233 }) 3234 } 3235 } 3236 3237 func TestParseLogSelectorExpr_equalityMatcher(t *testing.T) { 3238 for _, tc := range []struct { 3239 in string 3240 err error 3241 }{ 3242 { 3243 in: `{foo="bar"}`, 3244 }, 3245 { 3246 in: `{foo!="bar"}`, 3247 err: logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0), 3248 }, 3249 { 3250 in: `{app="baz", foo!="bar"}`, 3251 }, 3252 { 3253 in: `{app=~".+"}`, 3254 }, 3255 { 3256 in: `{app=~".*"}`, 3257 err: logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0), 3258 }, 3259 { 3260 in: `{foo=~"bar|baz"}`, 3261 }, 3262 { 3263 in: `{foo!~"bar|baz"}`, 3264 err: logqlmodel.NewParseError(errAtleastOneEqualityMatcherRequired, 0, 0), 3265 }, 3266 } { 3267 t.Run(tc.in, func(t *testing.T) { 3268 _, err := ParseLogSelector(tc.in, true) 3269 require.Equal(t, tc.err, err) 3270 }) 3271 } 3272 }