github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logql/syntax/ast.go (about) 1 package syntax 2 3 import ( 4 "fmt" 5 "math" 6 "regexp" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/pkg/errors" 12 "github.com/prometheus/common/model" 13 "github.com/prometheus/prometheus/model/labels" 14 "github.com/prometheus/prometheus/promql" 15 16 "github.com/grafana/loki/pkg/logql/log" 17 "github.com/grafana/loki/pkg/logqlmodel" 18 ) 19 20 // Expr is the root expression which can be a SampleExpr or LogSelectorExpr 21 type Expr interface { 22 logQLExpr() // ensure it's not implemented accidentally 23 Shardable() bool // A recursive check on the AST to see if it's shardable. 24 Walkable 25 fmt.Stringer 26 } 27 28 func Clone(e Expr) (Expr, error) { 29 return ParseExpr(e.String()) 30 } 31 32 // implicit holds default implementations 33 type implicit struct{} 34 35 func (implicit) logQLExpr() {} 36 37 // LogSelectorExpr is a LogQL expression filtering and returning logs. 38 type LogSelectorExpr interface { 39 Matchers() []*labels.Matcher 40 LogPipelineExpr 41 HasFilter() bool 42 Expr 43 } 44 45 // Type alias for backward compatibility 46 type ( 47 Pipeline = log.Pipeline 48 SampleExtractor = log.SampleExtractor 49 ) 50 51 // LogPipelineExpr is an expression defining a log pipeline. 52 type LogPipelineExpr interface { 53 Pipeline() (Pipeline, error) 54 Expr 55 } 56 57 // StageExpr is an expression defining a single step into a log pipeline 58 type StageExpr interface { 59 Stage() (log.Stage, error) 60 Expr 61 } 62 63 // MultiStageExpr is multiple stages which implement a PipelineExpr. 64 type MultiStageExpr []StageExpr 65 66 func (m MultiStageExpr) Pipeline() (log.Pipeline, error) { 67 stages, err := m.stages() 68 if err != nil { 69 return nil, err 70 } 71 return log.NewPipeline(stages), nil 72 } 73 74 func (m MultiStageExpr) stages() ([]log.Stage, error) { 75 c := make([]log.Stage, 0, len(m)) 76 for _, e := range m { 77 p, err := e.Stage() 78 if err != nil { 79 return nil, logqlmodel.NewStageError(e.String(), err) 80 } 81 if p == log.NoopStage { 82 continue 83 } 84 c = append(c, p) 85 } 86 return c, nil 87 } 88 89 func (m MultiStageExpr) String() string { 90 var sb strings.Builder 91 for i, e := range m { 92 sb.WriteString(e.String()) 93 if i+1 != len(m) { 94 sb.WriteString(" ") 95 } 96 } 97 return sb.String() 98 } 99 100 func (MultiStageExpr) logQLExpr() {} // nolint:unused 101 102 type MatchersExpr struct { 103 Mts []*labels.Matcher 104 implicit 105 } 106 107 func newMatcherExpr(matchers []*labels.Matcher) *MatchersExpr { 108 return &MatchersExpr{Mts: matchers} 109 } 110 111 func (e *MatchersExpr) Matchers() []*labels.Matcher { 112 return e.Mts 113 } 114 115 func (e *MatchersExpr) AppendMatchers(m []*labels.Matcher) { 116 e.Mts = append(e.Mts, m...) 117 } 118 119 func (e *MatchersExpr) Shardable() bool { return true } 120 121 func (e *MatchersExpr) Walk(f WalkFn) { f(e) } 122 123 func (e *MatchersExpr) String() string { 124 var sb strings.Builder 125 sb.WriteString("{") 126 for i, m := range e.Mts { 127 sb.WriteString(m.String()) 128 if i+1 != len(e.Mts) { 129 sb.WriteString(", ") 130 } 131 } 132 sb.WriteString("}") 133 return sb.String() 134 } 135 136 func (e *MatchersExpr) Pipeline() (log.Pipeline, error) { 137 return log.NewNoopPipeline(), nil 138 } 139 140 func (e *MatchersExpr) HasFilter() bool { 141 return false 142 } 143 144 type PipelineExpr struct { 145 MultiStages MultiStageExpr 146 Left *MatchersExpr 147 implicit 148 } 149 150 func newPipelineExpr(left *MatchersExpr, pipeline MultiStageExpr) LogSelectorExpr { 151 return &PipelineExpr{ 152 Left: left, 153 MultiStages: pipeline, 154 } 155 } 156 157 func (e *PipelineExpr) Shardable() bool { 158 for _, p := range e.MultiStages { 159 if !p.Shardable() { 160 return false 161 } 162 } 163 return true 164 } 165 166 func (e *PipelineExpr) Walk(f WalkFn) { 167 f(e) 168 169 if e.Left == nil { 170 return 171 } 172 173 xs := make([]Walkable, 0, len(e.MultiStages)+1) 174 xs = append(xs, e.Left) 175 for _, p := range e.MultiStages { 176 xs = append(xs, p) 177 } 178 walkAll(f, xs...) 179 } 180 181 func (e *PipelineExpr) Matchers() []*labels.Matcher { 182 return e.Left.Matchers() 183 } 184 185 func (e *PipelineExpr) String() string { 186 var sb strings.Builder 187 sb.WriteString(e.Left.String()) 188 sb.WriteString(" ") 189 sb.WriteString(e.MultiStages.String()) 190 return sb.String() 191 } 192 193 func (e *PipelineExpr) Pipeline() (log.Pipeline, error) { 194 return e.MultiStages.Pipeline() 195 } 196 197 // HasFilter returns true if the pipeline contains stage that can filter out lines. 198 func (e *PipelineExpr) HasFilter() bool { 199 for _, p := range e.MultiStages { 200 switch p.(type) { 201 case *LineFilterExpr, *LabelFilterExpr: 202 return true 203 default: 204 continue 205 } 206 } 207 return false 208 } 209 210 type LineFilterExpr struct { 211 Left *LineFilterExpr 212 Ty labels.MatchType 213 Match string 214 Op string 215 implicit 216 } 217 218 func newLineFilterExpr(ty labels.MatchType, op, match string) *LineFilterExpr { 219 return &LineFilterExpr{ 220 Ty: ty, 221 Match: match, 222 Op: op, 223 } 224 } 225 226 func newNestedLineFilterExpr(left *LineFilterExpr, right *LineFilterExpr) *LineFilterExpr { 227 return &LineFilterExpr{ 228 Left: left, 229 Ty: right.Ty, 230 Match: right.Match, 231 Op: right.Op, 232 } 233 } 234 235 func (e *LineFilterExpr) Walk(f WalkFn) { 236 f(e) 237 if e.Left == nil { 238 return 239 } 240 e.Left.Walk(f) 241 } 242 243 // AddFilterExpr adds a filter expression to a logselector expression. 244 func AddFilterExpr(expr LogSelectorExpr, ty labels.MatchType, op, match string) (LogSelectorExpr, error) { 245 filter := newLineFilterExpr(ty, op, match) 246 switch e := expr.(type) { 247 case *MatchersExpr: 248 return newPipelineExpr(e, MultiStageExpr{filter}), nil 249 case *PipelineExpr: 250 e.MultiStages = append(e.MultiStages, filter) 251 return e, nil 252 default: 253 return nil, fmt.Errorf("unknown LogSelector: %v+", expr) 254 } 255 } 256 257 func (e *LineFilterExpr) Shardable() bool { return true } 258 259 func (e *LineFilterExpr) String() string { 260 var sb strings.Builder 261 if e.Left != nil { 262 sb.WriteString(e.Left.String()) 263 sb.WriteString(" ") 264 } 265 switch e.Ty { 266 case labels.MatchRegexp: 267 sb.WriteString("|~") 268 case labels.MatchNotRegexp: 269 sb.WriteString("!~") 270 case labels.MatchEqual: 271 sb.WriteString("|=") 272 case labels.MatchNotEqual: 273 sb.WriteString("!=") 274 } 275 sb.WriteString(" ") 276 if e.Op == "" { 277 sb.WriteString(strconv.Quote(e.Match)) 278 return sb.String() 279 } 280 sb.WriteString(e.Op) 281 sb.WriteString("(") 282 sb.WriteString(strconv.Quote(e.Match)) 283 sb.WriteString(")") 284 return sb.String() 285 } 286 287 func (e *LineFilterExpr) Filter() (log.Filterer, error) { 288 acc := make([]log.Filterer, 0) 289 for curr := e; curr != nil; curr = curr.Left { 290 switch curr.Op { 291 case OpFilterIP: 292 var err error 293 next, err := log.NewIPLineFilter(curr.Match, curr.Ty) 294 if err != nil { 295 return nil, err 296 } 297 acc = append(acc, next) 298 default: 299 next, err := log.NewFilter(curr.Match, curr.Ty) 300 if err != nil { 301 return nil, err 302 } 303 acc = append(acc, next) 304 } 305 } 306 307 if len(acc) == 1 { 308 return acc[0], nil 309 } 310 311 // The accumulation is right to left so it needs to be reversed. 312 for i := len(acc)/2 - 1; i >= 0; i-- { 313 opp := len(acc) - 1 - i 314 acc[i], acc[opp] = acc[opp], acc[i] 315 } 316 317 return log.NewAndFilters(acc), nil 318 } 319 320 func (e *LineFilterExpr) Stage() (log.Stage, error) { 321 f, err := e.Filter() 322 if err != nil { 323 return nil, err 324 } 325 return f.ToStage(), nil 326 } 327 328 type LabelParserExpr struct { 329 Op string 330 Param string 331 implicit 332 } 333 334 func newLabelParserExpr(op, param string) *LabelParserExpr { 335 return &LabelParserExpr{ 336 Op: op, 337 Param: param, 338 } 339 } 340 341 func (e *LabelParserExpr) Shardable() bool { return true } 342 343 func (e *LabelParserExpr) Walk(f WalkFn) { f(e) } 344 345 func (e *LabelParserExpr) Stage() (log.Stage, error) { 346 switch e.Op { 347 case OpParserTypeJSON: 348 return log.NewJSONParser(), nil 349 case OpParserTypeLogfmt: 350 return log.NewLogfmtParser(), nil 351 case OpParserTypeRegexp: 352 return log.NewRegexpParser(e.Param) 353 case OpParserTypeUnpack: 354 return log.NewUnpackParser(), nil 355 case OpParserTypePattern: 356 return log.NewPatternParser(e.Param) 357 default: 358 return nil, fmt.Errorf("unknown parser operator: %s", e.Op) 359 } 360 } 361 362 func (e *LabelParserExpr) String() string { 363 var sb strings.Builder 364 sb.WriteString(OpPipe) 365 sb.WriteString(" ") 366 sb.WriteString(e.Op) 367 if e.Param != "" { 368 sb.WriteString(" ") 369 sb.WriteString(strconv.Quote(e.Param)) 370 } 371 return sb.String() 372 } 373 374 type LabelFilterExpr struct { 375 log.LabelFilterer 376 implicit 377 } 378 379 func newLabelFilterExpr(filterer log.LabelFilterer) *LabelFilterExpr { 380 return &LabelFilterExpr{ 381 LabelFilterer: filterer, 382 } 383 } 384 385 func (e *LabelFilterExpr) Shardable() bool { return true } 386 387 func (e *LabelFilterExpr) Walk(f WalkFn) { f(e) } 388 389 func (e *LabelFilterExpr) Stage() (log.Stage, error) { 390 switch ip := e.LabelFilterer.(type) { 391 case *log.IPLabelFilter: 392 return ip, ip.PatternError() 393 } 394 return e.LabelFilterer, nil 395 } 396 397 func (e *LabelFilterExpr) String() string { 398 return fmt.Sprintf("%s %s", OpPipe, e.LabelFilterer.String()) 399 } 400 401 type LineFmtExpr struct { 402 Value string 403 implicit 404 } 405 406 func newLineFmtExpr(value string) *LineFmtExpr { 407 return &LineFmtExpr{ 408 Value: value, 409 } 410 } 411 412 func (e *LineFmtExpr) Shardable() bool { return true } 413 414 func (e *LineFmtExpr) Walk(f WalkFn) { f(e) } 415 416 func (e *LineFmtExpr) Stage() (log.Stage, error) { 417 return log.NewFormatter(e.Value) 418 } 419 420 func (e *LineFmtExpr) String() string { 421 return fmt.Sprintf("%s %s %s", OpPipe, OpFmtLine, strconv.Quote(e.Value)) 422 } 423 424 type LabelFmtExpr struct { 425 Formats []log.LabelFmt 426 427 implicit 428 } 429 430 func newLabelFmtExpr(fmts []log.LabelFmt) *LabelFmtExpr { 431 return &LabelFmtExpr{ 432 Formats: fmts, 433 } 434 } 435 436 func (e *LabelFmtExpr) Shardable() bool { return false } 437 438 func (e *LabelFmtExpr) Walk(f WalkFn) { f(e) } 439 440 func (e *LabelFmtExpr) Stage() (log.Stage, error) { 441 return log.NewLabelsFormatter(e.Formats) 442 } 443 444 func (e *LabelFmtExpr) String() string { 445 var sb strings.Builder 446 sb.WriteString(fmt.Sprintf("%s %s ", OpPipe, OpFmtLabel)) 447 for i, f := range e.Formats { 448 sb.WriteString(f.Name) 449 sb.WriteString("=") 450 if f.Rename { 451 sb.WriteString(f.Value) 452 } else { 453 sb.WriteString(strconv.Quote(f.Value)) 454 } 455 if i+1 != len(e.Formats) { 456 sb.WriteString(",") 457 } 458 } 459 return sb.String() 460 } 461 462 type JSONExpressionParser struct { 463 Expressions []log.JSONExpression 464 465 implicit 466 } 467 468 func newJSONExpressionParser(expressions []log.JSONExpression) *JSONExpressionParser { 469 return &JSONExpressionParser{ 470 Expressions: expressions, 471 } 472 } 473 474 func (j *JSONExpressionParser) Shardable() bool { return true } 475 476 func (j *JSONExpressionParser) Walk(f WalkFn) { f(j) } 477 478 func (j *JSONExpressionParser) Stage() (log.Stage, error) { 479 return log.NewJSONExpressionParser(j.Expressions) 480 } 481 482 func (j *JSONExpressionParser) String() string { 483 var sb strings.Builder 484 sb.WriteString(fmt.Sprintf("%s %s ", OpPipe, OpParserTypeJSON)) 485 for i, exp := range j.Expressions { 486 sb.WriteString(exp.Identifier) 487 sb.WriteString("=") 488 sb.WriteString(strconv.Quote(exp.Expression)) 489 490 if i+1 != len(j.Expressions) { 491 sb.WriteString(",") 492 } 493 } 494 return sb.String() 495 } 496 497 func mustNewMatcher(t labels.MatchType, n, v string) *labels.Matcher { 498 m, err := labels.NewMatcher(t, n, v) 499 if err != nil { 500 panic(logqlmodel.NewParseError(err.Error(), 0, 0)) 501 } 502 return m 503 } 504 505 func mustNewFloat(s string) float64 { 506 n, err := strconv.ParseFloat(s, 64) 507 if err != nil { 508 panic(logqlmodel.NewParseError(fmt.Sprintf("unable to parse float: %s", err.Error()), 0, 0)) 509 } 510 return n 511 } 512 513 type UnwrapExpr struct { 514 Identifier string 515 Operation string 516 517 PostFilters []log.LabelFilterer 518 } 519 520 func (u UnwrapExpr) String() string { 521 var sb strings.Builder 522 if u.Operation != "" { 523 sb.WriteString(fmt.Sprintf(" %s %s %s(%s)", OpPipe, OpUnwrap, u.Operation, u.Identifier)) 524 } else { 525 sb.WriteString(fmt.Sprintf(" %s %s %s", OpPipe, OpUnwrap, u.Identifier)) 526 } 527 for _, f := range u.PostFilters { 528 sb.WriteString(fmt.Sprintf(" %s %s", OpPipe, f)) 529 } 530 return sb.String() 531 } 532 533 func (u *UnwrapExpr) addPostFilter(f log.LabelFilterer) *UnwrapExpr { 534 u.PostFilters = append(u.PostFilters, f) 535 return u 536 } 537 538 func newUnwrapExpr(id string, operation string) *UnwrapExpr { 539 return &UnwrapExpr{Identifier: id, Operation: operation} 540 } 541 542 type LogRange struct { 543 Left LogSelectorExpr 544 Interval time.Duration 545 Offset time.Duration 546 547 Unwrap *UnwrapExpr 548 549 implicit 550 } 551 552 // impls Stringer 553 func (r LogRange) String() string { 554 var sb strings.Builder 555 sb.WriteString(r.Left.String()) 556 if r.Unwrap != nil { 557 sb.WriteString(r.Unwrap.String()) 558 } 559 sb.WriteString(fmt.Sprintf("[%v]", model.Duration(r.Interval))) 560 if r.Offset != 0 { 561 offsetExpr := OffsetExpr{Offset: r.Offset} 562 sb.WriteString(offsetExpr.String()) 563 } 564 return sb.String() 565 } 566 567 func (r *LogRange) Shardable() bool { return r.Left.Shardable() } 568 569 func (r *LogRange) Walk(f WalkFn) { 570 f(r) 571 if r.Left == nil { 572 return 573 } 574 r.Left.Walk(f) 575 } 576 577 func newLogRange(left LogSelectorExpr, interval time.Duration, u *UnwrapExpr, o *OffsetExpr) *LogRange { 578 var offset time.Duration 579 if o != nil { 580 offset = o.Offset 581 } 582 return &LogRange{ 583 Left: left, 584 Interval: interval, 585 Unwrap: u, 586 Offset: offset, 587 } 588 } 589 590 type OffsetExpr struct { 591 Offset time.Duration 592 } 593 594 func (o *OffsetExpr) String() string { 595 var sb strings.Builder 596 sb.WriteString(fmt.Sprintf(" %s %s", OpOffset, o.Offset.String())) 597 return sb.String() 598 } 599 600 func newOffsetExpr(offset time.Duration) *OffsetExpr { 601 return &OffsetExpr{ 602 Offset: offset, 603 } 604 } 605 606 const ( 607 // vector ops 608 OpTypeSum = "sum" 609 OpTypeAvg = "avg" 610 OpTypeMax = "max" 611 OpTypeMin = "min" 612 OpTypeCount = "count" 613 OpTypeStddev = "stddev" 614 OpTypeStdvar = "stdvar" 615 OpTypeBottomK = "bottomk" 616 OpTypeTopK = "topk" 617 618 // range vector ops 619 OpRangeTypeCount = "count_over_time" 620 OpRangeTypeRate = "rate" 621 OpRangeTypeRateCounter = "rate_counter" 622 OpRangeTypeBytes = "bytes_over_time" 623 OpRangeTypeBytesRate = "bytes_rate" 624 OpRangeTypeAvg = "avg_over_time" 625 OpRangeTypeSum = "sum_over_time" 626 OpRangeTypeMin = "min_over_time" 627 OpRangeTypeMax = "max_over_time" 628 OpRangeTypeStdvar = "stdvar_over_time" 629 OpRangeTypeStddev = "stddev_over_time" 630 OpRangeTypeQuantile = "quantile_over_time" 631 OpRangeTypeFirst = "first_over_time" 632 OpRangeTypeLast = "last_over_time" 633 OpRangeTypeAbsent = "absent_over_time" 634 635 // binops - logical/set 636 OpTypeOr = "or" 637 OpTypeAnd = "and" 638 OpTypeUnless = "unless" 639 640 // binops - operations 641 OpTypeAdd = "+" 642 OpTypeSub = "-" 643 OpTypeMul = "*" 644 OpTypeDiv = "/" 645 OpTypeMod = "%" 646 OpTypePow = "^" 647 648 // binops - comparison 649 OpTypeCmpEQ = "==" 650 OpTypeNEQ = "!=" 651 OpTypeGT = ">" 652 OpTypeGTE = ">=" 653 OpTypeLT = "<" 654 OpTypeLTE = "<=" 655 656 // parsers 657 OpParserTypeJSON = "json" 658 OpParserTypeLogfmt = "logfmt" 659 OpParserTypeRegexp = "regexp" 660 OpParserTypeUnpack = "unpack" 661 OpParserTypePattern = "pattern" 662 663 OpFmtLine = "line_format" 664 OpFmtLabel = "label_format" 665 666 OpPipe = "|" 667 OpUnwrap = "unwrap" 668 OpOffset = "offset" 669 670 OpOn = "on" 671 OpIgnoring = "ignoring" 672 673 OpGroupLeft = "group_left" 674 OpGroupRight = "group_right" 675 676 // conversion Op 677 OpConvBytes = "bytes" 678 OpConvDuration = "duration" 679 OpConvDurationSeconds = "duration_seconds" 680 681 OpLabelReplace = "label_replace" 682 683 // function filters 684 OpFilterIP = "ip" 685 ) 686 687 func IsComparisonOperator(op string) bool { 688 switch op { 689 case OpTypeCmpEQ, OpTypeNEQ, OpTypeGT, OpTypeGTE, OpTypeLT, OpTypeLTE: 690 return true 691 default: 692 return false 693 } 694 } 695 696 // IsLogicalBinOp tests whether an operation is a logical/set binary operation 697 func IsLogicalBinOp(op string) bool { 698 switch op { 699 case OpTypeOr, OpTypeAnd, OpTypeUnless: 700 return true 701 default: 702 return false 703 } 704 } 705 706 // SampleExpr is a LogQL expression filtering logs and returning metric samples. 707 type SampleExpr interface { 708 // Selector is the LogQL selector to apply when retrieving logs. 709 Selector() LogSelectorExpr 710 Extractor() (SampleExtractor, error) 711 MatcherGroups() []MatcherRange 712 Expr 713 } 714 715 type RangeAggregationExpr struct { 716 Left *LogRange 717 Operation string 718 719 Params *float64 720 Grouping *Grouping 721 implicit 722 } 723 724 func newRangeAggregationExpr(left *LogRange, operation string, gr *Grouping, stringParams *string) SampleExpr { 725 var params *float64 726 if stringParams != nil { 727 if operation != OpRangeTypeQuantile { 728 panic(logqlmodel.NewParseError(fmt.Sprintf("parameter %s not supported for operation %s", *stringParams, operation), 0, 0)) 729 } 730 var err error 731 params = new(float64) 732 *params, err = strconv.ParseFloat(*stringParams, 64) 733 if err != nil { 734 panic(logqlmodel.NewParseError(fmt.Sprintf("invalid parameter for operation %s: %s", operation, err), 0, 0)) 735 } 736 737 } else { 738 if operation == OpRangeTypeQuantile { 739 panic(logqlmodel.NewParseError(fmt.Sprintf("parameter required for operation %s", operation), 0, 0)) 740 } 741 } 742 e := &RangeAggregationExpr{ 743 Left: left, 744 Operation: operation, 745 Grouping: gr, 746 Params: params, 747 } 748 if err := e.validate(); err != nil { 749 panic(logqlmodel.NewParseError(err.Error(), 0, 0)) 750 } 751 return e 752 } 753 754 func (e *RangeAggregationExpr) Selector() LogSelectorExpr { 755 return e.Left.Left 756 } 757 758 func (e *RangeAggregationExpr) MatcherGroups() []MatcherRange { 759 xs := e.Left.Left.Matchers() 760 if len(xs) > 0 { 761 return []MatcherRange{ 762 { 763 Matchers: xs, 764 Interval: e.Left.Interval, 765 Offset: e.Left.Offset, 766 }, 767 } 768 } 769 return nil 770 } 771 772 func (e RangeAggregationExpr) validate() error { 773 if e.Grouping != nil { 774 switch e.Operation { 775 case OpRangeTypeAvg, OpRangeTypeStddev, OpRangeTypeStdvar, OpRangeTypeQuantile, OpRangeTypeMax, OpRangeTypeMin, OpRangeTypeFirst, OpRangeTypeLast: 776 default: 777 return fmt.Errorf("grouping not allowed for %s aggregation", e.Operation) 778 } 779 } 780 if e.Left.Unwrap != nil { 781 switch e.Operation { 782 case OpRangeTypeAvg, OpRangeTypeSum, OpRangeTypeMax, OpRangeTypeMin, OpRangeTypeStddev, 783 OpRangeTypeStdvar, OpRangeTypeQuantile, OpRangeTypeRate, OpRangeTypeRateCounter, 784 OpRangeTypeAbsent, OpRangeTypeFirst, OpRangeTypeLast: 785 return nil 786 default: 787 return fmt.Errorf("invalid aggregation %s with unwrap", e.Operation) 788 } 789 } 790 switch e.Operation { 791 case OpRangeTypeBytes, OpRangeTypeBytesRate, OpRangeTypeCount, OpRangeTypeRate, OpRangeTypeAbsent: 792 return nil 793 default: 794 return fmt.Errorf("invalid aggregation %s without unwrap", e.Operation) 795 } 796 } 797 798 func (e RangeAggregationExpr) Validate() error { 799 return e.validate() 800 } 801 802 // impls Stringer 803 func (e *RangeAggregationExpr) String() string { 804 var sb strings.Builder 805 sb.WriteString(e.Operation) 806 sb.WriteString("(") 807 if e.Params != nil { 808 sb.WriteString(strconv.FormatFloat(*e.Params, 'f', -1, 64)) 809 sb.WriteString(",") 810 } 811 sb.WriteString(e.Left.String()) 812 sb.WriteString(")") 813 if e.Grouping != nil { 814 sb.WriteString(e.Grouping.String()) 815 } 816 return sb.String() 817 } 818 819 // impl SampleExpr 820 func (e *RangeAggregationExpr) Shardable() bool { 821 return shardableOps[e.Operation] && e.Left.Shardable() 822 } 823 824 func (e *RangeAggregationExpr) Walk(f WalkFn) { 825 f(e) 826 if e.Left == nil { 827 return 828 } 829 e.Left.Walk(f) 830 } 831 832 type Grouping struct { 833 Groups []string 834 Without bool 835 } 836 837 // impls Stringer 838 func (g Grouping) String() string { 839 var sb strings.Builder 840 if g.Without { 841 sb.WriteString(" without") 842 } else if len(g.Groups) > 0 { 843 sb.WriteString(" by") 844 } 845 846 if len(g.Groups) > 0 { 847 sb.WriteString("(") 848 sb.WriteString(strings.Join(g.Groups, ",")) 849 sb.WriteString(")") 850 } 851 852 return sb.String() 853 } 854 855 type VectorAggregationExpr struct { 856 Left SampleExpr 857 858 Grouping *Grouping 859 Params int 860 Operation string 861 implicit 862 } 863 864 func mustNewVectorAggregationExpr(left SampleExpr, operation string, gr *Grouping, params *string) SampleExpr { 865 var p int 866 var err error 867 switch operation { 868 case OpTypeBottomK, OpTypeTopK: 869 if params == nil { 870 panic(logqlmodel.NewParseError(fmt.Sprintf("parameter required for operation %s", operation), 0, 0)) 871 } 872 if p, err = strconv.Atoi(*params); err != nil { 873 panic(logqlmodel.NewParseError(fmt.Sprintf("invalid parameter %s(%s,", operation, *params), 0, 0)) 874 } 875 876 default: 877 if params != nil { 878 panic(logqlmodel.NewParseError(fmt.Sprintf("unsupported parameter for operation %s(%s,", operation, *params), 0, 0)) 879 } 880 } 881 if gr == nil { 882 gr = &Grouping{} 883 } 884 return &VectorAggregationExpr{ 885 Left: left, 886 Operation: operation, 887 Grouping: gr, 888 Params: p, 889 } 890 } 891 892 func (e *VectorAggregationExpr) MatcherGroups() []MatcherRange { 893 return e.Left.MatcherGroups() 894 } 895 896 func (e *VectorAggregationExpr) Selector() LogSelectorExpr { 897 return e.Left.Selector() 898 } 899 900 func (e *VectorAggregationExpr) Extractor() (log.SampleExtractor, error) { 901 // inject in the range vector extractor the outer groups to improve performance. 902 // This is only possible if the operation is a sum. Anything else needs all labels. 903 if r, ok := e.Left.(*RangeAggregationExpr); ok && canInjectVectorGrouping(e.Operation, r.Operation) { 904 // if the range vec operation has no grouping we can push down the vec one. 905 if r.Grouping == nil { 906 return r.extractor(e.Grouping) 907 } 908 } 909 return e.Left.Extractor() 910 } 911 912 // canInjectVectorGrouping tells if a vector operation can inject grouping into the nested range vector. 913 func canInjectVectorGrouping(vecOp, rangeOp string) bool { 914 if vecOp != OpTypeSum { 915 return false 916 } 917 switch rangeOp { 918 case OpRangeTypeBytes, OpRangeTypeBytesRate, OpRangeTypeSum, OpRangeTypeRate, OpRangeTypeCount: 919 return true 920 default: 921 return false 922 } 923 } 924 925 func (e *VectorAggregationExpr) String() string { 926 var params []string 927 if e.Params != 0 { 928 params = []string{fmt.Sprintf("%d", e.Params), e.Left.String()} 929 } else { 930 params = []string{e.Left.String()} 931 } 932 return formatOperation(e.Operation, e.Grouping, params...) 933 } 934 935 // impl SampleExpr 936 func (e *VectorAggregationExpr) Shardable() bool { 937 if e.Operation == OpTypeCount || e.Operation == OpTypeAvg { 938 if !e.Left.Shardable() { 939 return false 940 } 941 // count is shardable if labels are not mutated 942 // otherwise distinct values can be counted twice per shard 943 shardable := true 944 e.Left.Walk(func(e interface{}) { 945 switch e.(type) { 946 // LabelParserExpr is normally shardable, but not in this case. 947 // TODO(owen-d): I think LabelParserExpr is shardable 948 // for avg, but not for count. Let's refactor to make this 949 // cleaner. For now I'm disallowing sharding on both. 950 case *LabelParserExpr: 951 shardable = false 952 } 953 }) 954 return shardable 955 } 956 return shardableOps[e.Operation] && e.Left.Shardable() 957 } 958 959 func (e *VectorAggregationExpr) Walk(f WalkFn) { 960 f(e) 961 if e.Left == nil { 962 return 963 } 964 e.Left.Walk(f) 965 } 966 967 // VectorMatchCardinality describes the cardinality relationship 968 // of two Vectors in a binary operation. 969 type VectorMatchCardinality int 970 971 const ( 972 CardOneToOne VectorMatchCardinality = iota 973 CardManyToOne 974 CardOneToMany 975 ) 976 977 func (vmc VectorMatchCardinality) String() string { 978 switch vmc { 979 case CardOneToOne: 980 return "one-to-one" 981 case CardManyToOne: 982 return "many-to-one" 983 case CardOneToMany: 984 return "one-to-many" 985 } 986 panic("promql.VectorMatchCardinality.String: unknown match cardinality") 987 } 988 989 // VectorMatching describes how elements from two Vectors in a binary 990 // operation are supposed to be matched. 991 type VectorMatching struct { 992 // The cardinality of the two Vectors. 993 Card VectorMatchCardinality 994 // MatchingLabels contains the labels which define equality of a pair of 995 // elements from the Vectors. 996 MatchingLabels []string 997 // On includes the given label names from matching, 998 // rather than excluding them. 999 On bool 1000 // Include contains additional labels that should be included in 1001 // the result from the side with the lower cardinality. 1002 Include []string 1003 } 1004 1005 type BinOpOptions struct { 1006 ReturnBool bool 1007 VectorMatching *VectorMatching 1008 } 1009 1010 type BinOpExpr struct { 1011 SampleExpr 1012 RHS SampleExpr 1013 Op string 1014 Opts *BinOpOptions 1015 } 1016 1017 func (e *BinOpExpr) MatcherGroups() []MatcherRange { 1018 return append(e.SampleExpr.MatcherGroups(), e.RHS.MatcherGroups()...) 1019 } 1020 1021 func (e *BinOpExpr) String() string { 1022 op := e.Op 1023 if e.Opts != nil { 1024 if e.Opts.ReturnBool { 1025 op = fmt.Sprintf("%s bool", op) 1026 } 1027 if e.Opts.VectorMatching != nil { 1028 group := "" 1029 if e.Opts.VectorMatching.Card == CardManyToOne { 1030 group = OpGroupLeft 1031 } else if e.Opts.VectorMatching.Card == CardOneToMany { 1032 group = OpGroupRight 1033 } 1034 if e.Opts.VectorMatching.Include != nil { 1035 group = fmt.Sprintf("%s (%s)", group, strings.Join(e.Opts.VectorMatching.Include, ",")) 1036 } 1037 1038 if e.Opts.VectorMatching.On || e.Opts.VectorMatching.MatchingLabels != nil { 1039 on := OpOn 1040 if !e.Opts.VectorMatching.On { 1041 on = OpIgnoring 1042 } 1043 op = fmt.Sprintf("%s %s (%s) %s", op, on, strings.Join(e.Opts.VectorMatching.MatchingLabels, ","), group) 1044 } 1045 } 1046 } 1047 return fmt.Sprintf("(%s %s %s)", e.SampleExpr.String(), op, e.RHS.String()) 1048 } 1049 1050 // impl SampleExpr 1051 func (e *BinOpExpr) Shardable() bool { 1052 if e.Opts != nil && e.Opts.VectorMatching != nil { 1053 // prohibit sharding when we're changing the label groupings, such as on or ignoring 1054 return false 1055 } 1056 return shardableOps[e.Op] && e.SampleExpr.Shardable() && e.RHS.Shardable() 1057 } 1058 1059 func (e *BinOpExpr) Walk(f WalkFn) { 1060 walkAll(f, e.SampleExpr, e.RHS) 1061 } 1062 1063 func mustNewBinOpExpr(op string, opts *BinOpOptions, lhs, rhs Expr) SampleExpr { 1064 left, ok := lhs.(SampleExpr) 1065 if !ok { 1066 panic(logqlmodel.NewParseError(fmt.Sprintf( 1067 "unexpected type for left leg of binary operation (%s): %T", 1068 op, 1069 lhs, 1070 ), 0, 0)) 1071 } 1072 1073 right, ok := rhs.(SampleExpr) 1074 if !ok { 1075 panic(logqlmodel.NewParseError(fmt.Sprintf( 1076 "unexpected type for right leg of binary operation (%s): %T", 1077 op, 1078 rhs, 1079 ), 0, 0)) 1080 } 1081 1082 leftLit, lOk := left.(*LiteralExpr) 1083 rightLit, rOk := right.(*LiteralExpr) 1084 1085 if IsLogicalBinOp(op) { 1086 if lOk { 1087 panic(logqlmodel.NewParseError(fmt.Sprintf( 1088 "unexpected literal for left leg of logical/set binary operation (%s): %f", 1089 op, 1090 leftLit.Val, 1091 ), 0, 0)) 1092 } 1093 1094 if rOk { 1095 panic(logqlmodel.NewParseError(fmt.Sprintf( 1096 "unexpected literal for right leg of logical/set binary operation (%s): %f", 1097 op, 1098 rightLit.Val, 1099 ), 0, 0)) 1100 } 1101 } 1102 1103 // map expr like (1+1) -> 2 1104 if lOk && rOk { 1105 return reduceBinOp(op, leftLit, rightLit) 1106 } 1107 1108 return &BinOpExpr{ 1109 SampleExpr: left, 1110 RHS: right, 1111 Op: op, 1112 Opts: opts, 1113 } 1114 } 1115 1116 // Reduces a binary operation expression. A binop is reducible if both of its legs are literal expressions. 1117 // This is because literals need match all labels, which is currently difficult to encode into StepEvaluators. 1118 // Therefore, we ensure a binop can be reduced/simplified, maintaining the invariant that it does not have two literal legs. 1119 func reduceBinOp(op string, left, right *LiteralExpr) *LiteralExpr { 1120 merged := MergeBinOp( 1121 op, 1122 &promql.Sample{Point: promql.Point{V: left.Val}}, 1123 &promql.Sample{Point: promql.Point{V: right.Val}}, 1124 false, 1125 false, 1126 ) 1127 return &LiteralExpr{Val: merged.V} 1128 } 1129 1130 func MergeBinOp(op string, left, right *promql.Sample, filter, isVectorComparison bool) *promql.Sample { 1131 var merger func(left, right *promql.Sample) *promql.Sample 1132 1133 switch op { 1134 case OpTypeAdd: 1135 merger = func(left, right *promql.Sample) *promql.Sample { 1136 if left == nil || right == nil { 1137 return nil 1138 } 1139 res := promql.Sample{ 1140 Metric: left.Metric, 1141 Point: left.Point, 1142 } 1143 res.Point.V += right.Point.V 1144 return &res 1145 } 1146 1147 case OpTypeSub: 1148 merger = func(left, right *promql.Sample) *promql.Sample { 1149 if left == nil || right == nil { 1150 return nil 1151 } 1152 res := promql.Sample{ 1153 Metric: left.Metric, 1154 Point: left.Point, 1155 } 1156 res.Point.V -= right.Point.V 1157 return &res 1158 } 1159 1160 case OpTypeMul: 1161 merger = func(left, right *promql.Sample) *promql.Sample { 1162 if left == nil || right == nil { 1163 return nil 1164 } 1165 res := promql.Sample{ 1166 Metric: left.Metric, 1167 Point: left.Point, 1168 } 1169 res.Point.V *= right.Point.V 1170 return &res 1171 } 1172 1173 case OpTypeDiv: 1174 merger = func(left, right *promql.Sample) *promql.Sample { 1175 if left == nil || right == nil { 1176 return nil 1177 } 1178 res := promql.Sample{ 1179 Metric: left.Metric, 1180 Point: left.Point, 1181 } 1182 1183 // guard against divide by zero 1184 if right.Point.V == 0 { 1185 res.Point.V = math.NaN() 1186 } else { 1187 res.Point.V /= right.Point.V 1188 } 1189 return &res 1190 } 1191 1192 case OpTypeMod: 1193 merger = func(left, right *promql.Sample) *promql.Sample { 1194 if left == nil || right == nil { 1195 return nil 1196 } 1197 res := promql.Sample{ 1198 Metric: left.Metric, 1199 Point: left.Point, 1200 } 1201 // guard against divide by zero 1202 if right.Point.V == 0 { 1203 res.Point.V = math.NaN() 1204 } else { 1205 res.Point.V = math.Mod(res.Point.V, right.Point.V) 1206 } 1207 return &res 1208 } 1209 1210 case OpTypePow: 1211 merger = func(left, right *promql.Sample) *promql.Sample { 1212 if left == nil || right == nil { 1213 return nil 1214 } 1215 1216 res := promql.Sample{ 1217 Metric: left.Metric, 1218 Point: left.Point, 1219 } 1220 res.Point.V = math.Pow(left.Point.V, right.Point.V) 1221 return &res 1222 } 1223 1224 case OpTypeCmpEQ: 1225 merger = func(left, right *promql.Sample) *promql.Sample { 1226 if left == nil || right == nil { 1227 return nil 1228 } 1229 1230 res := &promql.Sample{ 1231 Metric: left.Metric, 1232 Point: left.Point, 1233 } 1234 1235 val := 0. 1236 if left.Point.V == right.Point.V { 1237 val = 1. 1238 } else if filter { 1239 return nil 1240 } 1241 res.Point.V = val 1242 return res 1243 } 1244 1245 case OpTypeNEQ: 1246 merger = func(left, right *promql.Sample) *promql.Sample { 1247 if left == nil || right == nil { 1248 return nil 1249 } 1250 1251 res := &promql.Sample{ 1252 Metric: left.Metric, 1253 Point: left.Point, 1254 } 1255 1256 val := 0. 1257 if left.Point.V != right.Point.V { 1258 val = 1. 1259 } else if filter { 1260 return nil 1261 } 1262 res.Point.V = val 1263 return res 1264 } 1265 1266 case OpTypeGT: 1267 merger = func(left, right *promql.Sample) *promql.Sample { 1268 if left == nil || right == nil { 1269 return nil 1270 } 1271 1272 res := &promql.Sample{ 1273 Metric: left.Metric, 1274 Point: left.Point, 1275 } 1276 1277 val := 0. 1278 if left.Point.V > right.Point.V { 1279 val = 1. 1280 } else if filter { 1281 return nil 1282 } 1283 res.Point.V = val 1284 return res 1285 } 1286 1287 case OpTypeGTE: 1288 merger = func(left, right *promql.Sample) *promql.Sample { 1289 if left == nil || right == nil { 1290 return nil 1291 } 1292 1293 res := &promql.Sample{ 1294 Metric: left.Metric, 1295 Point: left.Point, 1296 } 1297 1298 val := 0. 1299 if left.Point.V >= right.Point.V { 1300 val = 1. 1301 } else if filter { 1302 return nil 1303 } 1304 res.Point.V = val 1305 return res 1306 } 1307 1308 case OpTypeLT: 1309 merger = func(left, right *promql.Sample) *promql.Sample { 1310 if left == nil || right == nil { 1311 return nil 1312 } 1313 1314 res := &promql.Sample{ 1315 Metric: left.Metric, 1316 Point: left.Point, 1317 } 1318 1319 val := 0. 1320 if left.Point.V < right.Point.V { 1321 val = 1. 1322 } else if filter { 1323 return nil 1324 } 1325 res.Point.V = val 1326 return res 1327 } 1328 1329 case OpTypeLTE: 1330 merger = func(left, right *promql.Sample) *promql.Sample { 1331 if left == nil || right == nil { 1332 return nil 1333 } 1334 1335 res := &promql.Sample{ 1336 Metric: left.Metric, 1337 Point: left.Point, 1338 } 1339 1340 val := 0. 1341 if left.Point.V <= right.Point.V { 1342 val = 1. 1343 } else if filter { 1344 return nil 1345 } 1346 res.Point.V = val 1347 return res 1348 } 1349 1350 default: 1351 panic(errors.Errorf("should never happen: unexpected operation: (%s)", op)) 1352 } 1353 1354 res := merger(left, right) 1355 if !isVectorComparison { 1356 return res 1357 } 1358 1359 if filter { 1360 // if a filter-enabled vector-wise comparison has returned non-nil, 1361 // ensure we return the left hand side's value (2) instead of the 1362 // comparison operator's result (1: the truthy answer) 1363 if res != nil { 1364 return left 1365 } 1366 } 1367 return res 1368 } 1369 1370 type LiteralExpr struct { 1371 Val float64 1372 implicit 1373 } 1374 1375 func mustNewLiteralExpr(s string, invert bool) *LiteralExpr { 1376 n, err := strconv.ParseFloat(s, 64) 1377 if err != nil { 1378 panic(logqlmodel.NewParseError(fmt.Sprintf("unable to parse literal as a float: %s", err.Error()), 0, 0)) 1379 } 1380 1381 if invert { 1382 n = -n 1383 } 1384 1385 return &LiteralExpr{ 1386 Val: n, 1387 } 1388 } 1389 1390 func (e *LiteralExpr) String() string { 1391 return fmt.Sprint(e.Val) 1392 } 1393 1394 // literlExpr impls SampleExpr & LogSelectorExpr mainly to reduce the need for more complicated typings 1395 // to facilitate sum types. We'll be type switching when evaluating them anyways 1396 // and they will only be present in binary operation legs. 1397 func (e *LiteralExpr) Selector() LogSelectorExpr { return e } 1398 func (e *LiteralExpr) HasFilter() bool { return false } 1399 func (e *LiteralExpr) Shardable() bool { return true } 1400 func (e *LiteralExpr) Walk(f WalkFn) { f(e) } 1401 func (e *LiteralExpr) Pipeline() (log.Pipeline, error) { return log.NewNoopPipeline(), nil } 1402 func (e *LiteralExpr) Matchers() []*labels.Matcher { return nil } 1403 func (e *LiteralExpr) MatcherGroups() []MatcherRange { return nil } 1404 func (e *LiteralExpr) Extractor() (log.SampleExtractor, error) { return nil, nil } 1405 func (e *LiteralExpr) Value() float64 { return e.Val } 1406 1407 // helper used to impl Stringer for vector and range aggregations 1408 // nolint:interfacer 1409 func formatOperation(op string, grouping *Grouping, params ...string) string { 1410 nonEmptyParams := make([]string, 0, len(params)) 1411 for _, p := range params { 1412 if p != "" { 1413 nonEmptyParams = append(nonEmptyParams, p) 1414 } 1415 } 1416 1417 var sb strings.Builder 1418 sb.WriteString(op) 1419 if grouping != nil { 1420 sb.WriteString(grouping.String()) 1421 } 1422 sb.WriteString("(") 1423 sb.WriteString(strings.Join(nonEmptyParams, ",")) 1424 sb.WriteString(")") 1425 return sb.String() 1426 } 1427 1428 type LabelReplaceExpr struct { 1429 Left SampleExpr 1430 Dst string 1431 Replacement string 1432 Src string 1433 Regex string 1434 Re *regexp.Regexp 1435 1436 implicit 1437 } 1438 1439 func mustNewLabelReplaceExpr(left SampleExpr, dst, replacement, src, regex string) *LabelReplaceExpr { 1440 re, err := regexp.Compile("^(?:" + regex + ")$") 1441 if err != nil { 1442 panic(logqlmodel.NewParseError(fmt.Sprintf("invalid regex in label_replace: %s", err.Error()), 0, 0)) 1443 } 1444 return &LabelReplaceExpr{ 1445 Left: left, 1446 Dst: dst, 1447 Replacement: replacement, 1448 Src: src, 1449 Re: re, 1450 Regex: regex, 1451 } 1452 } 1453 1454 func (e *LabelReplaceExpr) Selector() LogSelectorExpr { 1455 return e.Left.Selector() 1456 } 1457 1458 func (e *LabelReplaceExpr) MatcherGroups() []MatcherRange { 1459 return e.Left.MatcherGroups() 1460 } 1461 1462 func (e *LabelReplaceExpr) Extractor() (SampleExtractor, error) { 1463 return e.Left.Extractor() 1464 } 1465 1466 func (e *LabelReplaceExpr) Shardable() bool { 1467 return false 1468 } 1469 1470 func (e *LabelReplaceExpr) Walk(f WalkFn) { 1471 f(e) 1472 if e.Left == nil { 1473 return 1474 } 1475 e.Left.Walk(f) 1476 } 1477 1478 func (e *LabelReplaceExpr) String() string { 1479 var sb strings.Builder 1480 sb.WriteString(OpLabelReplace) 1481 sb.WriteString("(") 1482 sb.WriteString(e.Left.String()) 1483 sb.WriteString(",") 1484 sb.WriteString(strconv.Quote(e.Dst)) 1485 sb.WriteString(",") 1486 sb.WriteString(strconv.Quote(e.Replacement)) 1487 sb.WriteString(",") 1488 sb.WriteString(strconv.Quote(e.Src)) 1489 sb.WriteString(",") 1490 sb.WriteString(strconv.Quote(e.Regex)) 1491 sb.WriteString(")") 1492 return sb.String() 1493 } 1494 1495 // shardableOps lists the operations which may be sharded. 1496 // topk, botk, max, & min all must be concatenated and then evaluated in order to avoid 1497 // potential data loss due to series distribution across shards. 1498 // For example, grouping by `cluster` for a `max` operation may yield 1499 // 2 results on the first shard and 10 results on the second. If we prematurely 1500 // calculated `max`s on each shard, the shard/label combination with `2` may be 1501 // discarded and some other combination with `11` may be reported falsely as the max. 1502 // 1503 // Explanation: this is my (owen-d) best understanding. 1504 // 1505 // For an operation to be shardable, first the sample-operation itself must be associative like (+, *) but not (%, /, ^). 1506 // Secondly, if the operation is part of a vector aggregation expression or utilizes logical/set binary ops, 1507 // the vector operation must be distributive over the sample-operation. 1508 // This ensures that the vector merging operation can be applied repeatedly to data in different shards. 1509 // references: 1510 // https://en.wikipedia.org/wiki/Associative_property 1511 // https://en.wikipedia.org/wiki/Distributive_property 1512 var shardableOps = map[string]bool{ 1513 // vector ops 1514 OpTypeSum: true, 1515 // avg is only marked as shardable because we remap it into sum/count. 1516 OpTypeAvg: true, 1517 OpTypeCount: true, 1518 1519 // range vector ops 1520 OpRangeTypeCount: true, 1521 OpRangeTypeRate: true, 1522 OpRangeTypeBytes: true, 1523 OpRangeTypeBytesRate: true, 1524 OpRangeTypeSum: true, 1525 OpRangeTypeMax: true, 1526 OpRangeTypeMin: true, 1527 1528 // binops - arith 1529 OpTypeAdd: true, 1530 OpTypeMul: true, 1531 } 1532 1533 type MatcherRange struct { 1534 Matchers []*labels.Matcher 1535 Interval, Offset time.Duration 1536 } 1537 1538 func MatcherGroups(expr Expr) []MatcherRange { 1539 switch e := expr.(type) { 1540 case SampleExpr: 1541 return e.MatcherGroups() 1542 case LogSelectorExpr: 1543 if xs := e.Matchers(); len(xs) > 0 { 1544 return []MatcherRange{ 1545 { 1546 Matchers: xs, 1547 }, 1548 } 1549 } 1550 return nil 1551 default: 1552 return nil 1553 } 1554 }