github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/ast/spl/spl.peg (about) 1 { 2 package spl 3 4 import ( 5 "regexp" 6 "time" 7 8 "github.com/siglens/siglens/pkg/ast" 9 "github.com/siglens/siglens/pkg/segment/aggregations" 10 "github.com/siglens/siglens/pkg/segment/query" 11 "github.com/siglens/siglens/pkg/segment/structs" 12 "github.com/siglens/siglens/pkg/segment/utils" 13 log "github.com/sirupsen/logrus" 14 ) 15 16 func getParseError(err error) error { 17 switch ev := err.(type) { 18 case errList: 19 if pe, ok := ev[0].(*parserError); ok { 20 return &ast.ParseError{ 21 Inner: pe.Inner, 22 Line: pe.pos.line, 23 Column: pe.pos.col, 24 Offset: pe.pos.offset, 25 Prefix: pe.prefix, 26 Expected: pe.expected, 27 } 28 } 29 } 30 return err 31 } 32 33 // Remove the first and last character of the string 34 func removeQuotes(s any) string { 35 str := s.(string) 36 if len(str) < 3 { 37 return "" 38 } 39 40 return str[1:len(str)-1] 41 } 42 43 // Check if it rename fields with similar names using a wildcard 44 func isRegexRename(originalPattern, newPattern string) (bool, error) { 45 oldWildcards := strings.Count(originalPattern, "*") 46 newWildcards := strings.Count(newPattern, "*") 47 48 if oldWildcards == 0 && newWildcards == 0 { 49 return false, nil 50 } else if oldWildcards > 0 && oldWildcards == newWildcards { 51 return true, nil 52 } else { 53 return false, errors.New("Patterns do not match") 54 } 55 } 56 57 func deMorgansLaw(node *ast.Node) { 58 switch node.NodeType { 59 case ast.NodeTerminal: 60 switch node.Comparison.Op { 61 case "=": 62 node.Comparison.Op = "!=" 63 case "!=": 64 node.Comparison.Op = "=" 65 case ">": 66 node.Comparison.Op = "<=" 67 case "<": 68 node.Comparison.Op = ">=" 69 case ">=": 70 node.Comparison.Op = "<" 71 case "<=": 72 node.Comparison.Op = ">" 73 default: 74 log.Errorf("deMorgansLaw: unexpected node comparison op: %v", node.Comparison.Op) 75 } 76 case ast.NodeAnd: 77 node.NodeType = ast.NodeOr 78 deMorgansLaw(node.Left) 79 deMorgansLaw(node.Right) 80 case ast.NodeOr: 81 node.NodeType = ast.NodeAnd 82 deMorgansLaw(node.Left) 83 deMorgansLaw(node.Right) 84 default: 85 log.Errorf("deMorgansLaw: unexpected NodeType: %v", node.NodeType) 86 } 87 } 88 89 //Generate NumericExpr struct for eval functions 90 func createNumericExpr(op string, leftNumericExpr *structs.NumericExpr, rightNumericExpr *structs.NumericExpr, numericExprMode structs.NumericExprMode) (*structs.NumericExpr, error) { 91 if leftNumericExpr == nil { 92 return nil, fmt.Errorf("expr cannot be nil") 93 } 94 95 return &structs.NumericExpr{ 96 IsTerminal: false, 97 Op: op, 98 Left: leftNumericExpr, 99 Right: rightNumericExpr, 100 NumericExprMode: numericExprMode, 101 }, nil 102 } 103 104 func transferUint8ToString(opName interface{}) (string, error){ 105 strData, ok := opName.([]byte) 106 if !ok { 107 return "", fmt.Errorf("opName is not a []byte") 108 } 109 110 opNameStr := string(strData) 111 return opNameStr, nil 112 } 113 114 func transferPCREToRE2(pattern string) string { 115 pattern = strings.Replace(pattern, "(?<", "(?P<", -1) 116 return pattern 117 } 118 119 func getRexColNames(pattern string) ([]string, error) { 120 re, err := regexp.Compile(`\?<(?P<GroupName>[a-zA-Z0-9_]+)>`) 121 if err != nil { 122 return nil, fmt.Errorf("getRexColNames: There are some errors in the pattern: %v", err) 123 } 124 matches := re.FindAllStringSubmatch(pattern, -1) 125 126 var rexColNames []string 127 for _, match := range matches { 128 rexColNames = append(rexColNames, match[1]) 129 } 130 131 return rexColNames, nil 132 } 133 134 type aggregator struct { 135 measureAgg *structs.MeasureAggregator 136 renameOutputField bool 137 outputFieldNewName string 138 } 139 140 type singleAggTemp struct { 141 aggregators []*aggregator 142 SplitByClause *structs.SplitByClause 143 } 144 145 type TxnArgs struct { 146 argOption string 147 arguments *structs.TransactionArguments 148 } 149 150 type TimechartArgs struct { 151 singleAggExpr *singleAggTemp 152 // Todo: Add eval clause expr. 153 tcOptions *structs.TcOptions 154 } 155 } 156 157 Start <- SPACE? initialSearch:(InitialSearchBlock) filterBlocks:(FilterBlock)* queryAggBlocks:(QueryAggergatorBlock)* SPACE? EOF { 158 var q ast.QueryStruct 159 q.SearchFilter = initialSearch.(*ast.Node) 160 161 // Join the InitialSearchBlock with the FilterBlocks with AND nodes. For a 162 // search like "A | B | C | D" we should generate the node structure below 163 // so that when we run the search it evaluates A first. 164 // 165 // AND 166 // / \ 167 // A AND 168 // / \ 169 // B AND 170 // / \ 171 // C D 172 173 filterBlocksSlice := filterBlocks.([]any) 174 switch len(filterBlocksSlice) { 175 case 0: 176 q.SearchFilter = initialSearch.(*ast.Node) 177 case 1: 178 q.SearchFilter = &ast.Node { 179 NodeType: ast.NodeAnd, 180 Left: initialSearch.(*ast.Node), 181 Right: filterBlocksSlice[0].(*ast.Node), 182 } 183 default: // len > 1 184 // Iterate backwards so we build the node structure mentioned above. 185 root := filterBlocksSlice[len(filterBlocksSlice) - 1].(*ast.Node) 186 for i := len(filterBlocksSlice) - 2; i > -1; i-- { 187 newRoot := &ast.Node { 188 NodeType: ast.NodeAnd, 189 Left: filterBlocksSlice[i].(*ast.Node), 190 Right: root, 191 } 192 193 root = newRoot 194 } 195 196 q.SearchFilter = &ast.Node { 197 NodeType: ast.NodeAnd, 198 Left: initialSearch.(*ast.Node), 199 Right: root, 200 } 201 } 202 203 if queryAggBlocks != nil { 204 queryAggSlice := queryAggBlocks.([]any) 205 206 if len(queryAggSlice) > 0 { 207 // Chain together all QueryAggergators. 208 q.PipeCommands = queryAggSlice[0].(*structs.QueryAggregators) 209 210 // Go to the end of the first chain. 211 curQueryAgg := q.PipeCommands 212 for ; curQueryAgg.Next != nil; curQueryAgg = curQueryAgg.Next {} 213 214 // Link the remaining chains. 215 for i := range queryAggSlice[1:] { 216 queryAgg := queryAggSlice[i + 1].(*structs.QueryAggregators) 217 curQueryAgg.Next = queryAgg 218 219 // Go to the end of this chain. 220 for ; curQueryAgg.Next != nil; curQueryAgg = curQueryAgg.Next {} 221 } 222 } 223 } 224 225 return q, nil 226 } 227 228 InitialSearchBlock <- CMD_SEARCH? clause:ClauseLevel4 { 229 return clause, nil 230 } 231 232 SearchBlock <- !(ALLCMD) CMD_SEARCH? clause:ClauseLevel4 { 233 return clause, nil 234 } 235 236 FilterBlock <- PIPE block:(SearchBlock / RegexBlock) { 237 return block, nil 238 } 239 240 // Returns *structs.QueryAggregators 241 QueryAggergatorBlock <- block:(FieldSelectBlock / AggregatorBlock / EvalBlock / WhereBlock / HeadBlock / RexBlock / StatisticBlock / RenameBlock / TimechartBlock / TransactionBlock / DedupBlock / SortBlock) { 242 queryAgg := block.(*structs.QueryAggregators) 243 return queryAgg, nil 244 } 245 246 FieldSelectBlock <- PIPE CMD_FIELDS op:("-" / "+")? EMPTY_OR_SPACE fields:FieldNameList { 247 columnsRequest := &structs.ColumnsRequest{} 248 if op == nil || string(op.([]byte)) == "+" { 249 columnsRequest.IncludeColumns = fields.([]string) 250 } else { 251 columnsRequest.ExcludeColumns = fields.([]string) 252 } 253 254 queryAggregator := &structs.QueryAggregators { 255 PipeCommandType: structs.OutputTransformType, 256 OutputTransforms: &structs.OutputTransforms { 257 OutputColumns: columnsRequest, 258 }, 259 } 260 261 return queryAggregator, nil 262 } 263 264 AggregatorBlock <- PIPE CMD_STATS aggs:AggregationList byFields:(GroupbyBlock)? { 265 aggNode := &structs.QueryAggregators{} 266 267 // Extract the MeasureAggregators and check if any of the aggregation fields 268 // need to be renamed. 269 aggsSlice := aggs.([]*aggregator) 270 measureAggs := make([]*structs.MeasureAggregator, len(aggsSlice)) 271 columnsRequest := &structs.ColumnsRequest{} 272 columnsRequest.RenameAggregationColumns = make(map[string]string, 0) 273 274 for i, agg := range aggsSlice { 275 measureAggs[i] = agg.measureAgg 276 277 if agg.renameOutputField { 278 columnsRequest.RenameAggregationColumns[measureAggs[i].String()] = agg.outputFieldNewName 279 } 280 } 281 282 // If any agg field was renamed, make a QueryAggregators for all the renames. 283 if len(columnsRequest.RenameAggregationColumns) > 0 { 284 renameNode := &structs.QueryAggregators { 285 PipeCommandType: structs.OutputTransformType, 286 OutputTransforms: &structs.OutputTransforms { 287 OutputColumns: columnsRequest, 288 }, 289 } 290 291 aggNode.Next = renameNode 292 } 293 294 if byFields == nil { 295 aggNode.PipeCommandType = structs.MeasureAggsType 296 aggNode.MeasureOperations = measureAggs 297 } else { 298 aggNode.PipeCommandType = structs.GroupByType 299 aggNode.GroupByRequest = &structs.GroupByRequest { 300 MeasureOperations: measureAggs, 301 GroupByColumns: byFields.([]string), 302 } 303 aggNode.BucketLimit = query.MAX_GRP_BUCKS 304 } 305 306 return aggNode, nil 307 } 308 309 GroupbyBlock <- BY fields:FieldNameList { 310 // Wildcard fields are not allowed. See https://docs.splunk.com/Documentation/Splunk/9.1.0/SearchReference/Stats 311 for _, field := range fields.([]string) { 312 if strings.Contains(field, "*") { 313 return nil, errors.New("BY clause cannot contain fields with wildcards") 314 } 315 } 316 317 return fields, nil 318 } 319 320 RegexBlock <- CMD_REGEX keyAndOp:(FieldName EqualityOperator)? str:QuotedString { 321 var key, op string 322 if keyAndOp == nil { 323 key = "*" 324 op = "=" 325 } else { 326 keyAndOpSlice := keyAndOp.([]any) 327 key = keyAndOpSlice[0].(string) 328 op = keyAndOpSlice[1].(string) 329 } 330 331 // Remove the quotation marks. 332 regex := str.(string) 333 regex = regex[1:len(regex) - 1] 334 335 node := &ast.Node { 336 NodeType: ast.NodeTerminal, 337 Comparison: ast.Comparison { 338 Op: op, 339 Field: key, 340 Values: regex, 341 ValueIsRegex: true, 342 }, 343 } 344 345 return node, nil 346 } 347 348 ClauseLevel4 <- first:ClauseLevel3 rest:((AND / SPACE) ClauseLevel3)* { 349 if rest == nil { 350 return first, nil 351 } 352 353 cur := first.(*ast.Node) 354 for _, v := range rest.([]any) { 355 parts := v.([]any) // This will be [(AND / SPACE), ClauseLevel3]. 356 cur = &ast.Node { 357 NodeType: ast.NodeAnd, 358 Left: cur, 359 Right: parts[1].(*ast.Node), 360 } 361 } 362 363 return cur, nil 364 } 365 366 ClauseLevel3 <- first:ClauseLevel2 rest:(OR ClauseLevel2)* { 367 if rest == nil { 368 return first, nil 369 } 370 371 cur := first.(*ast.Node) 372 for _, v := range rest.([]any) { 373 parts := v.([]any) // This will be [OR, ClauseLevel2]. 374 cur = &ast.Node { 375 NodeType: ast.NodeOr, 376 Left: cur, 377 Right: parts[1].(*ast.Node), 378 } 379 } 380 381 return cur, nil 382 } 383 384 ClauseLevel2 <- notList:NOT+ first:ClauseLevel1 { 385 // There's an issue with how queries with AST Not nodes are run, so use 386 // De Morgan's law to manipulate the expression. 387 node := first.(*ast.Node) 388 numNots := len(notList.([]any)) 389 390 if numNots % 2 == 1 { 391 deMorgansLaw(node) 392 } 393 394 return node, nil 395 } / clause:ClauseLevel1 { 396 return clause, nil 397 } 398 399 ClauseLevel1 <- L_PAREN clause:ClauseLevel4 R_PAREN { 400 return clause, nil 401 } / term:SearchTerm { 402 return term, nil 403 } 404 405 // Parsing the text of a Number as a String would succeed, so we need to try 406 // parsing as a FieldWithNumberValue first. 407 SearchTerm <- term:(FieldWithNumberValue / FieldWithBooleanValue / FieldWithStringValue) { 408 return term, nil 409 } 410 411 // To be finished: add (<eval-expression>) BY <split-by-clause> ) for expr; Limit option ... 412 TimechartBlock <- PIPE CMD_TIMECHART tcArgs:TimechartArgumentsList limitExpr:(LimitExpr)? { 413 aggNode := &structs.QueryAggregators{} 414 415 columnsRequest := &structs.ColumnsRequest{} 416 columnsRequest.RenameAggregationColumns = make(map[string]string, 0) 417 measureAggs := make([]*structs.MeasureAggregator, 0) 418 419 timechartExpr := &structs.TimechartExpr{} 420 byField := "" 421 422 if tcArgs == nil { 423 return nil, fmt.Errorf("spl peg: timechart: either single-agg or eval-expression by split-by-clause is required") 424 } 425 426 timechartArgs := tcArgs.(*TimechartArgs) 427 428 // Todo: Should add || timechartArgs.evalExpr == nil 429 if timechartArgs.singleAggExpr == nil { 430 return nil, fmt.Errorf("spl peg: timechart: either single-agg or eval-expression by split-by-clause is required") 431 } 432 433 var bOptions *structs.BinOptions 434 435 if timechartArgs.tcOptions != nil { 436 if timechartArgs.tcOptions.BinOptions != nil { 437 bOptions = timechartArgs.tcOptions.BinOptions 438 } 439 } 440 441 if timechartArgs.singleAggExpr != nil { 442 singleAgg := &structs.SingleAgg{} 443 aggTemp := timechartArgs.singleAggExpr 444 445 for i, agg := range aggTemp.aggregators { 446 measureAggs = append(measureAggs, agg.measureAgg) 447 448 if agg.renameOutputField { 449 measureAggs[i].StrEnc = agg.outputFieldNewName 450 } 451 } 452 453 singleAgg.MeasureOperations = measureAggs 454 timechartExpr.SingleAgg = singleAgg 455 456 if aggTemp.SplitByClause != nil { 457 byField = aggTemp.SplitByClause.Field 458 } 459 } 460 461 // TODO: if timechartArgs.evalExpr != nil {} 462 463 aggNode.PipeCommandType = structs.GroupByType 464 aggNode.GroupByRequest = &structs.GroupByRequest{ 465 MeasureOperations: measureAggs, 466 GroupByColumns: []string{"timestamp"}, 467 } 468 aggNode.BucketLimit = query.MAX_GRP_BUCKS 469 470 if bOptions == nil { 471 bOptions = &structs.BinOptions{ 472 SpanOptions: &structs.SpanOptions{ 473 DefaultSettings: true, 474 SpanLength: &structs.SpanLength{ 475 Num: 1, 476 TimeScalr: utils.TMMinute, 477 }, 478 }, 479 } 480 } 481 482 var limitExprTmp *structs.LimitExpr 483 if limitExpr != nil { 484 limitExprTmp = limitExpr.(*structs.LimitExpr) 485 if len(measureAggs) > 1 { 486 limitExprTmp.LimitScoreMode = structs.LSMByFreq 487 } 488 } 489 490 timeBucket := aggregations.InitTimeBucket(bOptions.SpanOptions.SpanLength.Num, bOptions.SpanOptions.SpanLength.TimeScalr, byField, limitExprTmp, len(measureAggs)) 491 aggNode.TimeHistogram = timeBucket 492 493 return aggNode, nil 494 } 495 496 // To be finished: <eval-expression> BY <split-by-clause> 497 // TimechartEvalExpr <- ... BY splitByClause:(SplitByClause) { 498 // } 499 500 TimechartArgumentsList <- first:TimechartArgument rest:(SPACE TimechartArgument)* { 501 restSlice := rest.([]any) 502 timechartArgs := &TimechartArgs{} 503 504 numArgs := 1 + len(restSlice) 505 506 for i :=0; i < numArgs; i++ { 507 508 var numArg interface{} 509 510 if i == 0 { 511 numArg = first 512 } else { 513 numArg = restSlice[i - 1].([]any)[1] 514 } 515 516 switch numArg.(type) { 517 case *singleAggTemp: 518 timechartArgs.singleAggExpr = numArg.(*singleAggTemp) 519 case *structs.TcOptions: 520 timechartArgs.tcOptions = numArg.(*structs.TcOptions) 521 default: 522 return nil, fmt.Errorf("Spl peg: Timechart: invalid timechart argument: %v", numArg) 523 } 524 } 525 526 return timechartArgs, nil 527 } 528 529 TimechartArgument <- tcArg:(SingleAggExpr / TcOptions) { 530 return tcArg, nil 531 } 532 533 SingleAggExpr <- aggs:AggregationList splitByClause:SplitByClause? { 534 singleAggExpr := &singleAggTemp { 535 aggregators: aggs.([]*aggregator), 536 } 537 538 if splitByClause != nil { 539 singleAggExpr.SplitByClause = splitByClause.(*structs.SplitByClause) 540 } 541 542 return singleAggExpr, nil 543 } 544 545 // Syntax: <field> (<tc-options>)... [<where-clause>] 546 // <where-clause> to be finished 547 SplitByClause <- BY field:FieldName { 548 splitByClause := &structs.SplitByClause { 549 Field: field.(string), 550 } 551 552 return splitByClause, nil 553 } 554 555 TcOptions <- option:(BinOptions / (TcOption)+) { 556 //Default value 557 tcOptions := &structs.TcOptions{ 558 UseNull: true, 559 UseOther: true, 560 NullStr: "null", 561 OtherStr: "other", 562 } 563 switch option.(type) { 564 case *structs.BinOptions: 565 tcOptions.BinOptions = option.(*structs.BinOptions) 566 case [][]string: 567 optionSlice := option.([]any) 568 for _, opt := range optionSlice { 569 optArr := opt.([]string) 570 switch optArr[0] { 571 case "usenull": 572 useNullBool, err := strconv.ParseBool(optArr[1]) 573 if err != nil { 574 return nil, fmt.Errorf("Spl peg: Timechart: TcOptions: %v", err) 575 } 576 tcOptions.UseNull = useNullBool 577 case "useother": 578 useOtherBool, err := strconv.ParseBool(optArr[1]) 579 if err != nil { 580 return nil, fmt.Errorf("Spl peg: Timechart: TcOptions: %v", err) 581 } 582 tcOptions.UseOther = useOtherBool 583 case "nullstr": 584 tcOptions.OtherStr = optArr[1] 585 case "otherstr": 586 tcOptions.OtherStr = optArr[1] 587 default: 588 return nil, fmt.Errorf("Spl peg: Timechart: TcOptions: invalid option: %v", optArr[0]) 589 } 590 } 591 default: 592 return nil, fmt.Errorf("Spl peg: Timechart: Invalid tcOptions %v", option) 593 } 594 return tcOptions, nil 595 } 596 597 TcOption <- SPACE tcOptionCMD:TcOptionCMD EQUAL val:EvalFieldToRead { 598 tcOptionArr := []string{tcOptionCMD.(string), val.(string)} 599 return tcOptionArr, nil 600 } 601 602 TcOptionCMD <- option:("usenull" / "useother" / "nullstr" / "otherstr") { 603 optionStr, err := transferUint8ToString(option) 604 if err != nil { 605 return nil, fmt.Errorf("Spl peg: Timechart: TcOptionCMD: %v", err) 606 } 607 return optionStr, nil 608 } 609 610 // To be finished: bins=<int> | minspan=<span-length> | span | <start-end>: (end=<num> | start=<num>) | aligntime=(earliest | latest | <time-specifier>) 611 BinOptions <- spanOptions:SpanOptions { 612 binOptions := &structs.BinOptions { 613 SpanOptions: spanOptions.(*structs.SpanOptions), 614 } 615 return binOptions, nil 616 } 617 618 // To be finished: span=<log-span> | span=<span-length> | span=<snap-to-time> 619 SpanOptions <- CMD_SPAN EQUAL spanLength:SpanLength { 620 spanOptions := &structs.SpanOptions { 621 SpanLength: spanLength.(*structs.SpanLength), 622 } 623 return spanOptions, nil 624 } 625 626 SpanLength <- intAsStr:IntegerAsString timeScale:TimeScale{ 627 num, err := strconv.Atoi(intAsStr.(string)) 628 if err != nil { 629 return nil, fmt.Errorf("SpanLength: Invalid num (%v): %v", intAsStr.(string), err) 630 } 631 632 spanLength := &structs.SpanLength { 633 Num: num, 634 TimeScalr: timeScale.(utils.TimeUnit), 635 } 636 return spanLength, nil 637 } 638 639 TimeScale <- timeUnit:(Second / Minute / Hour / Day/ Week / Month / Quarter/ Subseconds) { 640 return timeUnit, nil 641 } 642 643 // limit=topN keeps the N highest scoring distinct values of the split-by field 644 LimitExpr <- SPACE "limit" EQUAL sortBy:("top" / "bottom")? EMPTY_OR_SPACE intAsStr:(IntegerAsString){ 645 num, err := strconv.Atoi(intAsStr.(string)) 646 if err != nil { 647 return nil, fmt.Errorf("SpanLength: Invalid num (%v): %v", intAsStr.(string), err) 648 } 649 650 limitExpr := &structs.LimitExpr { 651 IsTop: true, // Default Value 652 Num: num, 653 } 654 655 if sortBy != nil { 656 sortByStr, err := transferUint8ToString(sortBy) 657 if err != nil { 658 return nil, fmt.Errorf("Spl peg: Timechart: %v", err) 659 } 660 if sortByStr == "bottom" { 661 limitExpr.IsTop = false 662 } 663 } 664 665 return limitExpr, nil 666 } 667 668 StatisticBlock <- PIPE statisticExpr:StatisticExpr { 669 letColReq := &structs.LetColumnsRequest { 670 StatisticColRequest: statisticExpr.(*structs.StatisticExpr), 671 } 672 673 root := &structs.QueryAggregators { 674 PipeCommandType: structs.OutputTransformType, 675 OutputTransforms: &structs.OutputTransforms { 676 LetColumns: letColReq, 677 }, 678 } 679 680 measureAgg := &structs.MeasureAggregator { 681 MeasureCol: "*", 682 MeasureFunc: utils.Count, 683 } 684 685 measureOperations := make([]*structs.MeasureAggregator, 1) 686 measureOperations[0] = measureAgg 687 688 groupByColumns := append(statisticExpr.(*structs.StatisticExpr).FieldList, statisticExpr.(*structs.StatisticExpr).ByClause...) 689 690 aggNode := &structs.QueryAggregators{} 691 aggNode.Next = root 692 aggNode.PipeCommandType = structs.GroupByType 693 aggNode.GroupByRequest = &structs.GroupByRequest { 694 MeasureOperations: measureOperations, 695 GroupByColumns: groupByColumns, 696 } 697 698 return aggNode, nil 699 } 700 701 StatisticExpr <- cmd:(CMD_TOP / CMD_RARE) limit:(StatisticLimit)? fieldList:(SPACE FieldNameList) byClause:(ByClause)? options:(StatisticOptions)? { 702 703 statisticExpr := &structs.StatisticExpr { 704 FieldList: fieldList.([]interface{})[1].([]string), 705 } 706 707 statisticCmd, err := transferUint8ToString(cmd) 708 if err != nil { 709 return nil, fmt.Errorf("Spl peg: StatisticExpr: %v", err) 710 } 711 712 if(statisticCmd == "top"){ 713 statisticExpr.StatisticFunctionMode = structs.SFMTop 714 } else { 715 statisticExpr.StatisticFunctionMode = structs.SFMRare 716 } 717 718 if limit != nil { 719 statisticExpr.Limit = limit.(string) 720 } 721 722 if options != nil { 723 statisticExpr.StatisticOptions = options.(*structs.StatisticOptions) 724 } else { 725 statisticExpr.StatisticOptions = &structs.StatisticOptions { 726 ShowCount: true, 727 CountField: "count", 728 ShowPerc: true, 729 PercentField: "percent", 730 UseOther: false, 731 OtherStr: "Other", 732 } 733 } 734 735 if byClause != nil { 736 statisticExpr.ByClause = byClause.([]string) 737 } 738 739 return statisticExpr, nil 740 } 741 742 // Top limit=<int> is the same as specifying top N. 743 StatisticLimit <- SPACE number:IntegerAsString { 744 return number.(string), nil 745 } 746 / SPACE "limit" EQUAL limit:(IntegerAsString) { 747 return limit.(string), nil 748 } 749 750 // Optional arguments for top/rare functions 751 StatisticOptions <- option:(StatisticOption)* 752 { 753 //Default value 754 options := &structs.StatisticOptions { 755 ShowCount: true, 756 CountField: "count", 757 ShowPerc: true, 758 PercentField: "percent", 759 UseOther: false, 760 OtherStr: "other", 761 } 762 763 optionSlice := option.([]any) 764 for _, opt := range optionSlice { 765 optArr := opt.([]string) 766 // Check for matching option types 767 switch optArr[0] { 768 case "showcount": 769 showCountBool, err := strconv.ParseBool(optArr[1]) 770 if err != nil { 771 return nil, fmt.Errorf("Spl peg: StatisticBlock: Options: %v", err) 772 } 773 options.ShowCount = showCountBool 774 case "countfield": 775 options.CountField = optArr[1] 776 case "showperc": 777 showPercBool, err := strconv.ParseBool(optArr[1]) 778 if err != nil { 779 return nil, fmt.Errorf("Spl peg: StatisticBlock: Options: %v", err) 780 } 781 options.ShowPerc = showPercBool 782 case "percentfield": 783 options.PercentField = optArr[1] 784 case "useother": 785 useOtherBool, err := strconv.ParseBool(optArr[1]) 786 if err != nil { 787 return nil, fmt.Errorf("Spl peg: StatisticBlock: Options: %v", err) 788 } 789 options.UseOther = useOtherBool 790 case "otherstr": 791 options.OtherStr = optArr[1] 792 default: 793 return nil, fmt.Errorf("Spl peg: StatisticBlock: Options: invalid option") 794 } 795 } 796 797 return options, nil 798 } 799 800 StatisticOption <- SPACE optionCMD:StatisticOptionCMD EQUAL field:EvalFieldToRead { 801 optionArr := []string{optionCMD.(string), field.(string)} 802 return optionArr, nil 803 } 804 805 StatisticOptionCMD <- option:("countfield" / "showcount" / "otherstr" / "useother"/ "percentfield" / "showperc") { 806 optionStr, err := transferUint8ToString(option) 807 if err != nil { 808 return nil, fmt.Errorf("Spl peg: StatisticExpr: %v", err) 809 } 810 return optionStr, nil 811 } 812 813 ByClause <- BY fieldList:FieldNameList { 814 return fieldList.([]string), nil 815 } 816 / groupByBlock:GroupbyBlock { 817 return groupByBlock.([]string), nil 818 } 819 820 DedupBlock <- PIPE CMD_DEDUP dedupExpr:DedupExpr { 821 822 letColReq := &structs.LetColumnsRequest { 823 DedupColRequest: dedupExpr.(*structs.DedupExpr), 824 } 825 826 root := &structs.QueryAggregators { 827 PipeCommandType: structs.OutputTransformType, 828 OutputTransforms: &structs.OutputTransforms { 829 LetColumns: letColReq, 830 }, 831 } 832 833 return root, nil 834 } 835 836 // Returns *structs.DedupExpr 837 // It's not clear in the Splunk documentation whether the DedupOptions should 838 // be before or after the field list. However, the field list probably 839 // shouldn't be after the sortby clause. 840 DedupExpr <- limitArr:(SPACE IntegerAsString)? options1:(DedupOptions)? fieldList:(DedupFieldList)? options2:(DedupOptions)? sortByClause:(DedupSortByClause)? { 841 dedupExpr := &structs.DedupExpr { 842 FieldList: fieldList.([]string), 843 Limit: 1, 844 DedupCombinations: make(map[string]map[int][]structs.SortValue, 0), 845 DedupRecords: make(map[string]map[string]interface{}, 0), 846 } 847 848 if limitArr != nil { 849 limitStr := limitArr.([]interface{})[1].(string) 850 limit, err := strconv.ParseUint(limitStr, 10, 64) 851 if err != nil || limit == 0 { 852 return nil, fmt.Errorf("Invalid limit (%v): %v", limitStr, err) 853 } 854 dedupExpr.Limit = limit 855 } 856 857 dedupExpr.DedupOptions = &structs.DedupOptions { 858 Consecutive: false, 859 KeepEmpty: false, 860 KeepEvents: false, 861 } 862 863 if options1 != nil { 864 dedupExpr.DedupOptions = options1.(*structs.DedupOptions) 865 } 866 if options2 != nil { 867 options := options2.(*structs.DedupOptions) 868 869 if options.Consecutive { 870 dedupExpr.DedupOptions.Consecutive = options.Consecutive 871 } 872 if options.KeepEmpty { 873 dedupExpr.DedupOptions.KeepEmpty = options.KeepEmpty 874 } 875 if options.KeepEvents { 876 dedupExpr.DedupOptions.KeepEvents = options.KeepEvents 877 } 878 } 879 880 if sortByClause != nil { 881 dedupExpr.DedupSortEles = sortByClause.([]*structs.SortElement) 882 883 // Make the DedupSortAscending from the DedupSortEles. 884 dedupExpr.DedupSortAscending = make([]int, len(dedupExpr.DedupSortEles)) 885 for i, ele := range dedupExpr.DedupSortEles { 886 if ele.SortByAsc { 887 dedupExpr.DedupSortAscending[i] = 1 888 } else { 889 dedupExpr.DedupSortAscending[i] = -1 890 } 891 } 892 } 893 894 return dedupExpr, nil 895 } 896 897 DedupFieldName <- !("sortby") field:FieldName { 898 return field, nil 899 } 900 901 DedupFieldList <- SPACE first:DedupFieldName rest:(SPACE DedupFieldName !EQUAL)* { 902 // Convert `rest` to a slice. Each element of the slice will be a 2-element 903 // slice where the first element is " " and the second is a FieldName. 904 restSlice := rest.([]any) 905 906 numFieldNames := 1 + len(restSlice) 907 fields := make([]string, numFieldNames) 908 fields[0] = first.(string) 909 910 for i := 1; i < numFieldNames; i++ { 911 separatorAndField := restSlice[i - 1].([]any) 912 fields[i] = separatorAndField[1].(string) 913 } 914 915 return fields, nil 916 } 917 918 // Optional arguments for dedup block 919 DedupOptions <- option:(DedupOption)* 920 { 921 //Default value 922 options := &structs.DedupOptions { 923 Consecutive: false, 924 KeepEmpty: false, 925 KeepEvents: false, 926 } 927 928 optionSlice := option.([]any) 929 for _, opt := range optionSlice { 930 optArr := opt.([]string) 931 // Check for matching option types 932 switch optArr[0] { 933 case "consecutive": 934 consecutiveBool, err := strconv.ParseBool(optArr[1]) 935 if err != nil { 936 return nil, fmt.Errorf("Spl peg: DedupBlock: Options: %v", err) 937 } 938 options.Consecutive = consecutiveBool 939 case "keepempty": 940 keepEmptyBool, err := strconv.ParseBool(optArr[1]) 941 if err != nil { 942 return nil, fmt.Errorf("Spl peg: DedupBlock: Options: %v", err) 943 } 944 options.KeepEmpty = keepEmptyBool 945 case "keepevents": 946 keepEventsBool, err := strconv.ParseBool(optArr[1]) 947 if err != nil { 948 return nil, fmt.Errorf("Spl peg: DedupBlock: Options: %v", err) 949 } 950 options.KeepEvents = keepEventsBool 951 default: 952 return nil, fmt.Errorf("Spl peg: DedupBlock: Options: invalid option") 953 } 954 } 955 956 return options, nil 957 } 958 959 DedupOption <- SPACE optionCMD:DedupOptionCMD "=" field:EvalFieldToRead { 960 optionArr := []string{optionCMD.(string), field.(string)} 961 return optionArr, nil 962 } 963 964 DedupOptionCMD <- option:("consecutive" / "keepempty" / "keepevents") { 965 optionStr, err := transferUint8ToString(option) 966 if err != nil { 967 return nil, fmt.Errorf("Spl peg: DedupExpr: %v", err) 968 } 969 return optionStr, nil 970 } 971 972 DedupSortByClause <- CMD_DEDUP_SORTBY dedupSortEles:SortElements { 973 return dedupSortEles, nil 974 } 975 976 // sortby ( - | + ) <sort-field> [(- | +) <sort_field> ...] 977 SortElements <- first:SingleSortElement rest:(EMPTY_OR_COMMA SingleSortElement)* { 978 restSlice := rest.([]any) 979 980 length := 1 + len(restSlice) 981 sortEles := make([]*structs.SortElement, length) 982 sortEles[0] = first.(*structs.SortElement) 983 984 for i := 1; i < length; i++ { 985 elements := restSlice[i - 1].([]any) 986 sortEles[i] = elements[1].(*structs.SortElement) 987 } 988 989 return sortEles, nil 990 } 991 992 SingleSortElement <- element:(SingleSortElementWithCast / SingleSortElementWithoutCast) { 993 return element, nil 994 } 995 996 SingleSortElementWithoutCast <- sortBySymbol:("+" / "-" / "") field:FieldName { 997 sortByAsc := true 998 999 symbol := sortBySymbol.([]byte) 1000 if(len(symbol) > 0 && symbol[0] == '-') { 1001 sortByAsc = false 1002 } 1003 1004 return &structs.SortElement { 1005 SortByAsc: sortByAsc, 1006 Op: "", 1007 Field: field.(string), 1008 }, nil 1009 } 1010 1011 SingleSortElementWithCast <- sortBySymbol:("+" / "-" / "") op:("auto" / "str" / "ip" / "num") L_PAREN field:FieldName R_PAREN { 1012 sortByAsc := true 1013 1014 symbol := sortBySymbol.([]byte) 1015 if(len(symbol) > 0 && symbol[0] == '-') { 1016 sortByAsc = false 1017 } 1018 1019 opStr, err := transferUint8ToString(op) 1020 if err != nil { 1021 return nil, fmt.Errorf("Spl peg: singleSortElementWithCast: %v", err) 1022 } 1023 1024 return &structs.SortElement { 1025 SortByAsc: sortByAsc, 1026 Op: opStr, 1027 Field: field.(string), 1028 }, nil 1029 } 1030 1031 RenameBlock <- PIPE CMD_RENAME renameExpr:RenameExpr { 1032 letColReq := &structs.LetColumnsRequest { 1033 RenameColRequest: renameExpr.(*structs.RenameExpr), 1034 } 1035 1036 root := &structs.QueryAggregators { 1037 PipeCommandType: structs.OutputTransformType, 1038 OutputTransforms: &structs.OutputTransforms { 1039 LetColumns: letColReq, 1040 }, 1041 } 1042 1043 return root, nil 1044 } 1045 1046 // Rename with a phrase 1047 RenameExpr <- originalPattern:RenamePattern AS newPattern:QuotedString { 1048 renameExpr := &structs.RenameExpr { 1049 RenameExprMode: structs.REMPhrase, 1050 OriginalPattern: originalPattern.(string), 1051 NewPattern: removeQuotes(newPattern), 1052 } 1053 1054 return renameExpr, nil 1055 } 1056 // Rename fields with similar names using a wildcard 1057 // Or Rename to a existing field 1058 / originalPattern:RenamePattern AS newPattern:RenamePattern { 1059 isRegex, err := isRegexRename(originalPattern.(string), newPattern.(string)) 1060 if err != nil { 1061 return nil, fmt.Errorf("Spl peg: RenameExpr: %v", err) 1062 } 1063 1064 var renameExprMode structs.RenameExprMode 1065 if isRegex { 1066 renameExprMode = structs.REMRegex 1067 } else { 1068 renameExprMode = structs.REMOverride 1069 } 1070 1071 renameExpr := &structs.RenameExpr { 1072 RenameExprMode: renameExprMode, 1073 OriginalPattern: originalPattern.(string), 1074 NewPattern: newPattern.(string), 1075 } 1076 1077 return renameExpr, nil 1078 } 1079 1080 RexBlock <- PIPE CMD_REX "field" EQUAL field:EvalFieldToRead SPACE str:QuotedString { 1081 pattern := removeQuotes(str) 1082 rexColNames, err := getRexColNames(pattern) 1083 if err != nil { 1084 return nil, fmt.Errorf("Spl peg: RexBlock: %v", err) 1085 } 1086 rexExpr := &structs.RexExpr { 1087 FieldName: field.(string), 1088 Pattern: transferPCREToRE2(pattern), 1089 RexColNames: rexColNames, 1090 } 1091 1092 letColReq := &structs.LetColumnsRequest { 1093 RexColRequest: rexExpr, 1094 } 1095 1096 root := &structs.QueryAggregators { 1097 PipeCommandType: structs.OutputTransformType, 1098 OutputTransforms: &structs.OutputTransforms { 1099 LetColumns: letColReq, 1100 }, 1101 } 1102 1103 return root, nil 1104 } 1105 1106 // arguments need to be finished: 1107 // [<count>], [desc] 1108 SortBlock <- PIPE CMD_SORT sortByEles:SortElements { 1109 1110 sortExpr := &structs.SortExpr { 1111 SortEles: sortByEles.([]*structs.SortElement), 1112 SortRecords: make(map[string]map[string]interface{}, 0), 1113 } 1114 1115 ascendingArr := make([]int, len(sortExpr.SortEles)) 1116 for i, ele := range sortExpr.SortEles { 1117 if ele.SortByAsc { 1118 ascendingArr[i] = 1 1119 } else { 1120 ascendingArr[i] = -1 1121 } 1122 } 1123 1124 sortExpr.SortAscending = ascendingArr 1125 1126 letColReq := &structs.LetColumnsRequest { 1127 SortColRequest: sortExpr, 1128 } 1129 1130 root := &structs.QueryAggregators { 1131 PipeCommandType: structs.OutputTransformType, 1132 OutputTransforms: &structs.OutputTransforms { 1133 LetColumns: letColReq, 1134 }, 1135 } 1136 1137 return root, nil 1138 } 1139 1140 // Returns *structs.QueryAggregators 1141 EvalBlock <- PIPE CMD_EVAL first:SingleEval rest:(COMMA SingleEval)* { 1142 root := &structs.QueryAggregators { 1143 PipeCommandType: structs.OutputTransformType, 1144 OutputTransforms: &structs.OutputTransforms { 1145 LetColumns: first.(*structs.LetColumnsRequest), 1146 }, 1147 } 1148 1149 leafQueryAgg := root 1150 restSlice := rest.([]any) 1151 for i := range restSlice { 1152 CommaSpaceAndEval := restSlice[i].([]any) 1153 nextQueryAgg := &structs.QueryAggregators { 1154 PipeCommandType: structs.OutputTransformType, 1155 OutputTransforms: &structs.OutputTransforms { 1156 LetColumns: CommaSpaceAndEval[1].(*structs.LetColumnsRequest), 1157 }, 1158 } 1159 1160 leafQueryAgg.Next = nextQueryAgg 1161 leafQueryAgg = leafQueryAgg.Next 1162 } 1163 1164 return root, nil 1165 } 1166 1167 // Returns *structs.LetColumnsRequest 1168 SingleEval <- field:FieldName EQUAL expr:EvalExpression { 1169 fieldStr := field.(string) 1170 if strings.Contains(fieldStr, "*") { 1171 return nil, fmt.Errorf("New fields must not contain wildcards; invalid field: %v", field) 1172 } 1173 1174 letColumnsRequest := expr.(*structs.LetColumnsRequest) 1175 letColumnsRequest.NewColName = fieldStr 1176 1177 return letColumnsRequest, nil 1178 } 1179 1180 // Returns *structs.LetColumnsRequest without the NewColName set. 1181 EvalExpression <- value:ValueExpr { 1182 letColReq := &structs.LetColumnsRequest { 1183 ValueColRequest: value.(*structs.ValueExpr), 1184 } 1185 1186 return letColReq, nil 1187 } 1188 1189 ConditionExpr <- "if" L_PAREN condition:BoolExpr COMMA trueValue:ValueExpr COMMA falseValue:ValueExpr R_PAREN { 1190 1191 node := &structs.ConditionExpr { 1192 Op: "if", 1193 BoolExpr: condition.(*structs.BoolExpr), 1194 TrueValue: trueValue.(*structs.ValueExpr), 1195 FalseValue: falseValue.(*structs.ValueExpr), 1196 } 1197 1198 return node, nil 1199 } 1200 1201 TextExpr <- (opName:("lower") L_PAREN stringExpr:StringExpr R_PAREN) { 1202 opNameStr, err := transferUint8ToString(opName) 1203 if err != nil { 1204 return nil, fmt.Errorf("Spl peg: TextExpr: %v", err) 1205 } 1206 node := &structs.TextExpr { 1207 Op: opNameStr, 1208 Value: stringExpr.(*structs.StringExpr), 1209 StrToRemove: "", 1210 } 1211 1212 return node, nil 1213 } 1214 1215 / (opName:("max" / "min") L_PAREN firstVal:StringExpr rest:(COMMA StringExpr)* R_PAREN ) 1216 { 1217 opNameStr, err := transferUint8ToString(opName) 1218 if err != nil { 1219 return nil, fmt.Errorf("Spl peg: TextExpr: %v", err) 1220 } 1221 if rest == nil { 1222 return firstVal, nil 1223 } 1224 restSlice := rest.([]any) 1225 values := make([]*structs.StringExpr, 1 + len(restSlice)) 1226 values[0] = firstVal.(*structs.StringExpr) 1227 1228 for i := range restSlice { 1229 stringAtom := restSlice[i].([]any) 1230 values[i + 1] = stringAtom[1].(*structs.StringExpr) 1231 } 1232 node := &structs.TextExpr { 1233 Op: opNameStr, 1234 MaxMinValues: values, 1235 } 1236 return node, nil 1237 } 1238 / (opName:("urldecode") L_PAREN url:StringExpr R_PAREN ){ 1239 opNameStr, err := transferUint8ToString(opName) 1240 if err != nil { 1241 return nil, fmt.Errorf("Spl peg: TextExpr: %v", err) 1242 } 1243 node := &structs.TextExpr { 1244 Op: opNameStr, 1245 Value: url.(*structs.StringExpr), 1246 StrToRemove: "", 1247 } 1248 return node, nil 1249 } 1250 / (opName:("split") L_PAREN stringExpr:StringExpr COMMA delim:StringExpr R_PAREN) { 1251 opNameStr, err := transferUint8ToString(opName) 1252 if err != nil { 1253 return nil, fmt.Errorf("Spl peg: TextExpr: %v", err) 1254 } 1255 node := &structs.TextExpr { 1256 Op: opNameStr, 1257 Value: stringExpr.(*structs.StringExpr), 1258 Delimiter: delim.(*structs.StringExpr), 1259 } 1260 return node, nil 1261 } 1262 / (opName:("substr") L_PAREN stringExpr:StringExpr COMMA startIndex:NumericExpr lengthParam:(COMMA NumericExpr)? R_PAREN) { 1263 opNameStr, err := transferUint8ToString(opName) 1264 if err != nil { 1265 return nil, fmt.Errorf("Spl peg: TextExpr: %v", err) 1266 } 1267 stringExprConverted, ok := stringExpr.(*structs.StringExpr) 1268 if !ok { 1269 return nil, fmt.Errorf("Spl peg: TextExpr: Failed to assert stringExpr as *structs.StringExpr") 1270 } 1271 startIndexConverted, ok := startIndex.(*structs.NumericExpr) 1272 if !ok { 1273 return nil, fmt.Errorf("Spl peg: TextExpr: Failed to assert startIndex as *structs.NumericExpr") 1274 } 1275 var lengthConverted *structs.NumericExpr 1276 if lengthParam != nil { 1277 lengthSlice, ok := lengthParam.([]interface{}) 1278 if ok && len(lengthSlice) > 1 { 1279 length, ok := lengthSlice[1].(*structs.NumericExpr) 1280 if ok { 1281 lengthConverted = length 1282 } else { 1283 return nil, fmt.Errorf("Spl peg: TextExpr: Unable to assert length as *structs.NumericExpr") 1284 } 1285 } 1286 } 1287 node := &structs.TextExpr { 1288 Op: opNameStr, 1289 Value: stringExprConverted, 1290 StartIndex: startIndexConverted, 1291 LengthExpr: lengthConverted, 1292 } 1293 return node, nil 1294 } 1295 / "tostring" L_PAREN value:ValueExpr format:(COMMA StringExpr )? R_PAREN { 1296 var formatExpr *structs.StringExpr 1297 if format != nil { 1298 formatSlice := format.([]interface{}) 1299 formatExpr, _ = formatSlice[1].(*structs.StringExpr) 1300 } 1301 return &structs.TextExpr{ 1302 IsTerminal: false, 1303 Op: "tostring", 1304 Val: value.(*structs.ValueExpr), 1305 Format: formatExpr, 1306 }, nil 1307 } 1308 / (opName:("ltrim" / "rtrim") L_PAREN expr:(StringExpr) strToRemoveExpr:(StrToRemoveExpr)? R_PAREN) { 1309 opNameStr, err := transferUint8ToString(opName) 1310 if err != nil { 1311 return nil, fmt.Errorf("Spl peg: TextExpr: %v", err) 1312 } 1313 1314 stringExpr, ok := expr.(*structs.StringExpr) 1315 if !ok { 1316 return nil, fmt.Errorf("Spl peg: TextExpr: Failed to assert expr as *structs.StringExpr: %v", err) 1317 } 1318 1319 strToRemove := " \t" 1320 if strToRemoveExpr != nil { 1321 strToRemove = strToRemoveExpr.(string) 1322 } 1323 1324 node := &structs.TextExpr { 1325 Op: opNameStr, 1326 Value: stringExpr, 1327 StrToRemove: removeQuotes(strToRemove), 1328 } 1329 1330 return node, nil 1331 } 1332 1333 StrToRemoveExpr <- COMMA strToRemove:String { 1334 return strToRemove, nil 1335 } 1336 1337 // From https://docs.splunk.com/Documentation/Splunk/9.1.0/SearchReference/Eval#Syntax 1338 // Returns the field as a string with no quotation marks. 1339 EvalFieldToRead <- [a-zA-Z_]+ !("(") { 1340 return string(c.text), nil 1341 } 1342 / "'" field:FieldName "'" { 1343 return field, nil 1344 } 1345 1346 // Returns *structs.QueryAggregators 1347 WhereBlock <- PIPE CMD_WHERE condition:BoolExpr { 1348 queryAgg := &structs.QueryAggregators { 1349 PipeCommandType: structs.OutputTransformType, 1350 OutputTransforms: &structs.OutputTransforms { 1351 FilterRows: condition.(*structs.BoolExpr), 1352 }, 1353 } 1354 1355 return queryAgg, nil 1356 } 1357 1358 // Returns *structs.BoolExpr 1359 BoolExpr <- expr:BoolExprLevel4 { 1360 return expr, nil 1361 } 1362 1363 // Returns *structs.BoolExpr 1364 BoolExprLevel4 <- first:BoolExprLevel3 rest:(OR BoolExprLevel3)* { 1365 if rest == nil { 1366 return first, nil 1367 } 1368 1369 cur := first.(*structs.BoolExpr) 1370 for _, v := range rest.([]any) { 1371 opAndClause := v.([]any) 1372 cur = &structs.BoolExpr { 1373 IsTerminal: false, 1374 BoolOp: structs.BoolOpOr, 1375 LeftBool: cur, 1376 RightBool: opAndClause[1].(*structs.BoolExpr), 1377 } 1378 } 1379 1380 return cur, nil 1381 } 1382 1383 // Returns *structs.BoolExpr 1384 BoolExprLevel3 <- first:BoolExprLevel2 rest:(AND BoolExprLevel2)* { 1385 if rest == nil { 1386 return first, nil 1387 } 1388 1389 cur := first.(*structs.BoolExpr) 1390 for _, v := range rest.([]any) { 1391 opAndClause := v.([]any) 1392 cur = &structs.BoolExpr { 1393 IsTerminal: false, 1394 BoolOp: structs.BoolOpAnd, 1395 LeftBool: cur, 1396 RightBool: opAndClause[1].(*structs.BoolExpr), 1397 } 1398 } 1399 1400 return cur, nil 1401 } 1402 1403 // Returns *structs.BoolExpr 1404 BoolExprLevel2 <- NOT L_PAREN first:BoolExprLevel1 R_PAREN { 1405 cur := &structs.BoolExpr { 1406 IsTerminal: false, 1407 BoolOp: structs.BoolOpNot, 1408 LeftBool: first.(*structs.BoolExpr), 1409 RightBool: nil, 1410 } 1411 1412 return cur, nil 1413 } 1414 / first:BoolExprLevel1 { 1415 return first, nil 1416 } 1417 1418 // Returns *structs.BoolExpr 1419 BoolExprLevel1 <- L_PAREN first:BoolExprLevel4 R_PAREN { 1420 return first, nil 1421 } 1422 / (op:("isbool" / "isint" / "isstr" / "isnull") L_PAREN value:ValueExpr R_PAREN ) { 1423 opNameStr, err := transferUint8ToString(op) 1424 if err != nil { 1425 return nil, fmt.Errorf("Spl peg: BoolExpr: %v", err) 1426 } 1427 expr := &structs.BoolExpr { 1428 IsTerminal: true, 1429 LeftValue: value.(*structs.ValueExpr), 1430 RightValue: nil, 1431 ValueOp: opNameStr, 1432 } 1433 return expr, nil 1434 } 1435 / likeExpr: LikeExpr { 1436 return likeExpr, nil 1437 } 1438 LikeExpr <- left:ValueExpr SPACE "LIKE" SPACE right:ValueExpr { 1439 expr := &structs.BoolExpr { 1440 IsTerminal: true, 1441 LeftValue: left.(*structs.ValueExpr), 1442 RightValue: right.(*structs.ValueExpr), 1443 ValueOp: "like", 1444 } 1445 return expr, nil 1446 } 1447 / "like" L_PAREN stringr:ValueExpr COMMA pattern:ValueExpr R_PAREN { 1448 expr := &structs.BoolExpr { 1449 IsTerminal: true, 1450 LeftValue: stringr.(*structs.ValueExpr), 1451 RightValue: pattern.(*structs.ValueExpr), 1452 ValueOp: "like", 1453 } 1454 return expr, nil 1455 } 1456 / "match" L_PAREN stringVal:ValueExpr COMMA pattern:ValueExpr R_PAREN { 1457 expr := &structs.BoolExpr { 1458 IsTerminal: true, 1459 LeftValue: stringVal.(*structs.ValueExpr), 1460 RightValue: pattern.(*structs.ValueExpr), 1461 ValueOp: "match", 1462 } 1463 return expr, nil 1464 } 1465 / "cidrmatch" L_PAREN cidr:ValueExpr COMMA ip:ValueExpr R_PAREN { 1466 expr := &structs.BoolExpr { 1467 IsTerminal: true, 1468 LeftValue: cidr.(*structs.ValueExpr), 1469 RightValue: ip.(*structs.ValueExpr), 1470 ValueOp: "cidrmatch", 1471 } 1472 return expr, nil 1473 } 1474 / inExpr: InExpr { 1475 return inExpr, nil 1476 } 1477 / boolComparisonExpr:BoolComparisonExpr { 1478 return boolComparisonExpr, nil 1479 } 1480 1481 BoolComparisonExpr <- left:ValueExpr op:EqualityOrInequality right:ValueExpr { 1482 expr := &structs.BoolExpr { 1483 IsTerminal: true, 1484 LeftValue: left.(*structs.ValueExpr), 1485 RightValue: right.(*structs.ValueExpr), 1486 ValueOp: op.(string), 1487 } 1488 1489 return expr, nil 1490 } 1491 1492 1493 InExpr <- left:ValueExpr SPACE "in" L_PAREN valueToJudge:ValueExpr rest:(COMMA ValueExpr)* R_PAREN { 1494 restSlice := rest.([]any) 1495 slice := make([]*structs.ValueExpr, 1 + len(restSlice)) 1496 slice[0] = valueToJudge.(*structs.ValueExpr) 1497 1498 for i := range restSlice { 1499 valueAtom := restSlice[i].([]any) 1500 slice[i + 1] = valueAtom[1].(*structs.ValueExpr) 1501 } 1502 1503 expr := &structs.BoolExpr { 1504 IsTerminal: true, 1505 LeftValue: left.(*structs.ValueExpr), 1506 ValueList: slice, 1507 ValueOp: "in", 1508 } 1509 return expr, nil 1510 } 1511 // For this in use case: if(in(<value>, [<list>]), "true_value", "false_value") 1512 / "in" L_PAREN valueToJudge:ValueExpr rest:(COMMA ValueExpr)* R_PAREN { 1513 restSlice := rest.([]any) 1514 slice := make([]*structs.ValueExpr, len(restSlice)) 1515 1516 for i := range restSlice { 1517 valueAtom := restSlice[i].([]any) 1518 slice[i] = valueAtom[1].(*structs.ValueExpr) 1519 } 1520 1521 expr := &structs.BoolExpr { 1522 IsTerminal: true, 1523 LeftValue: valueToJudge.(*structs.ValueExpr), 1524 ValueList: slice, 1525 ValueOp: "in", 1526 } 1527 return expr, nil 1528 } 1529 1530 // Returns *structs.ValueExpr 1531 // 1532 // The order of the choices is important. In particular, we want to parse a 1533 // single field as a VEMField type ValueExpr so that it can be evaluated to 1534 // either a string or float as needed (if the field has float values), rather 1535 // than parsing it as a NumericExpr or ConcatExpr and forcing it to be a float 1536 // or string respectively. 1537 ValueExpr <- condition:ConditionExpr { 1538 1539 expr := &structs.ValueExpr { 1540 ValueExprMode: structs.VEMConditionExpr, 1541 ConditionExpr: condition.(*structs.ConditionExpr), 1542 } 1543 1544 return expr, nil 1545 } 1546 / L_PAREN (condition:ConditionExpr) R_PAREN { 1547 1548 expr := &structs.ValueExpr { 1549 ValueExprMode: structs.VEMConditionExpr, 1550 ConditionExpr: condition.(*structs.ConditionExpr), 1551 } 1552 1553 return expr, nil 1554 } 1555 / numeric:NumericExpr { 1556 1557 expr := &structs.ValueExpr { 1558 ValueExprMode: structs.VEMNumericExpr, 1559 NumericExpr: numeric.(*structs.NumericExpr), 1560 } 1561 1562 return expr, nil 1563 } 1564 / str:StringExpr { 1565 1566 expr := &structs.ValueExpr { 1567 ValueExprMode: structs.VEMStringExpr, 1568 StringExpr: str.(*structs.StringExpr), 1569 } 1570 1571 return expr, nil 1572 } 1573 / L_PAREN (str:StringExpr) R_PAREN { 1574 1575 expr := &structs.ValueExpr { 1576 ValueExprMode: structs.VEMStringExpr, 1577 StringExpr: str.(*structs.StringExpr), 1578 } 1579 1580 return expr, nil 1581 } 1582 / L_PAREN boolean:BoolExpr R_PAREN { 1583 1584 expr := &structs.ValueExpr{ 1585 ValueExprMode: structs.VEMBooleanExpr, 1586 BooleanExpr: boolean.(*structs.BoolExpr), 1587 } 1588 1589 return expr, nil 1590 } 1591 1592 StringExpr <- text:TextExpr !(EVAL_CONCAT) { 1593 expr := &structs.StringExpr { 1594 StringExprMode: structs.SEMTextExpr, 1595 TextExpr: text.(*structs.TextExpr), 1596 } 1597 1598 return expr, nil 1599 } 1600 / str:QuotedString !(EVAL_CONCAT) { 1601 expr := &structs.StringExpr { 1602 StringExprMode: structs.SEMRawString, 1603 RawString: removeQuotes(str), 1604 } 1605 1606 return expr, nil 1607 } 1608 / field:EvalFieldToRead !(OpPlus / OpMinus / OpMul / OpDiv / EVAL_CONCAT / "(") { 1609 expr := &structs.StringExpr { 1610 StringExprMode: structs.SEMField, 1611 FieldName: field.(string), 1612 } 1613 1614 return expr, nil 1615 } 1616 / concat:ConcatExpr { 1617 expr := &structs.StringExpr { 1618 StringExprMode: structs.SEMConcatExpr, 1619 ConcatExpr: concat.(*structs.ConcatExpr), 1620 } 1621 1622 return expr, nil 1623 } 1624 1625 // Returns *structs.ConcatExpr 1626 ConcatExpr <- first:ConcatAtom rest:(EVAL_CONCAT ConcatAtom)* !(OpPlus / OpMinus / OpMul / OpDiv / "(") { 1627 restSlice := rest.([]any) 1628 slice := make([]*structs.ConcatAtom, 1 + len(restSlice)) 1629 slice[0] = first.(*structs.ConcatAtom) 1630 1631 for i := range restSlice { 1632 concatAndAtom := restSlice[i].([]any) 1633 slice[i + 1] = concatAndAtom[1].(*structs.ConcatAtom) 1634 } 1635 1636 expr := &structs.ConcatExpr { 1637 Atoms: slice, 1638 } 1639 1640 return expr, nil 1641 } 1642 1643 // Returns *structs.ConcatAtom 1644 ConcatAtom <- text:TextExpr { 1645 atom := &structs.ConcatAtom { 1646 IsField: false, 1647 Value: "", 1648 TextExpr: text.(*structs.TextExpr), 1649 } 1650 1651 return atom, nil 1652 } 1653 / str:QuotedString { 1654 atom := &structs.ConcatAtom { 1655 IsField: false, 1656 Value: removeQuotes(str), 1657 } 1658 1659 return atom, nil 1660 } 1661 / number:NumberAsString { 1662 atom := &structs.ConcatAtom { 1663 IsField: false, 1664 Value: number.(string), 1665 } 1666 1667 return atom, nil 1668 } 1669 / field:EvalFieldToRead { 1670 atom := &structs.ConcatAtom { 1671 IsField: true, 1672 Value: field.(string), 1673 } 1674 1675 return atom, nil 1676 } 1677 1678 // Returns *structs.NumericExpr 1679 NumericExpr <- expr:NumericExprLevel3 !(EVAL_CONCAT / "\"" ) { 1680 return expr, nil 1681 } 1682 1683 // Returns *structs.NumericExpr 1684 NumericExprLevel3 <- first:NumericExprLevel2 rest:((OpPlus / OpMinus) NumericExprLevel2)* { 1685 if rest == nil { 1686 return first, nil 1687 } 1688 1689 cur := first.(*structs.NumericExpr) 1690 for _, v := range rest.([]any) { 1691 opAndClause := v.([]any) 1692 cur = &structs.NumericExpr { 1693 IsTerminal: false, 1694 Op: opAndClause[0].(string), 1695 Left: cur, 1696 Right: opAndClause[1].(*structs.NumericExpr), 1697 NumericExprMode: structs.NEMNumericExpr, 1698 } 1699 } 1700 1701 return cur, nil 1702 } 1703 1704 // Returns *structs.NumericExpr 1705 NumericExprLevel2 <- first:NumericExprLevel1 rest:((OpMul / OpDiv) NumericExprLevel1)* { 1706 if rest == nil { 1707 return first, nil 1708 } 1709 1710 cur := first.(*structs.NumericExpr) 1711 for _, v := range rest.([]any) { 1712 opAndClause := v.([]any) 1713 cur = &structs.NumericExpr { 1714 IsTerminal: false, 1715 Op: opAndClause[0].(string), 1716 Left: cur, 1717 Right: opAndClause[1].(*structs.NumericExpr), 1718 NumericExprMode: structs.NEMNumericExpr, 1719 } 1720 } 1721 1722 return cur, nil 1723 } 1724 1725 RoundPrecisionExpr <- COMMA expr:NumericExprLevel3 { 1726 rightNumericExpr, ok := expr.(*structs.NumericExpr) 1727 if !ok { 1728 return nil, fmt.Errorf("Failed to assert expr as *structs.NumericExpr") 1729 } 1730 1731 return rightNumericExpr, nil 1732 } 1733 1734 // Returns *structs.NumericExpr 1735 NumericExprLevel1 <- L_PAREN expr:NumericExprLevel3 R_PAREN { 1736 return expr, nil 1737 } 1738 / numericEvalExpr: NumericEvalExpr { 1739 return numericEvalExpr, nil 1740 } 1741 / field:EvalFieldToRead { 1742 expr := &structs.NumericExpr { 1743 IsTerminal: true, 1744 ValueIsField: true, 1745 Value: field.(string), 1746 NumericExprMode: structs.NEMNumberField, 1747 } 1748 1749 return expr, nil 1750 } 1751 / number:NumberAsString { 1752 expr := &structs.NumericExpr { 1753 IsTerminal: true, 1754 ValueIsField: false, 1755 Value: number.(string), 1756 NumericExprMode: structs.NEMNumber, 1757 } 1758 1759 return expr, nil 1760 } 1761 1762 //Currently involves abs, ceil, round, sqrt 1763 NumericEvalExpr <- (opName:("abs" / "ceil" / "sqrt"/ "exact"/ "exp") L_PAREN expr:(NumericExprLevel3) R_PAREN) { 1764 leftNumericExpr, ok := expr.(*structs.NumericExpr) 1765 if !ok { 1766 return nil, fmt.Errorf("Failed to assert expr as *structs.NumericExpr") 1767 } 1768 1769 //transfer []uint8 to string 1770 strData, ok := opName.([]byte) 1771 if !ok { 1772 return nil, fmt.Errorf("opName is not a []byte") 1773 } 1774 1775 opNameStr := string(strData) 1776 node, err := createNumericExpr(opNameStr, leftNumericExpr, nil, structs.NEMNumericExpr) 1777 if err != nil { 1778 return nil, err 1779 } 1780 1781 return node, nil 1782 } 1783 / roundExpr:"round" L_PAREN expr:(NumericExprLevel3) roundPrecision:(RoundPrecisionExpr)? R_PAREN { 1784 leftNumericExpr, ok := expr.(*structs.NumericExpr) 1785 if !ok { 1786 return nil, fmt.Errorf("Failed to assert expr as *structs.NumericExpr") 1787 } 1788 1789 var rightNumericExpr *structs.NumericExpr 1790 if roundPrecision != nil { 1791 rightNumericExpr, ok = roundPrecision.(*structs.NumericExpr) 1792 if !ok { 1793 return nil, fmt.Errorf("Failed to assert roundPrecision as *structs.NumericExpr") 1794 } 1795 } 1796 1797 node, err := createNumericExpr("round", leftNumericExpr, rightNumericExpr, structs.NEMNumericExpr) 1798 if err != nil { 1799 return nil, err 1800 } 1801 1802 return node, nil 1803 } 1804 / "now" "()" { 1805 return &structs.NumericExpr{ 1806 IsTerminal: true, 1807 Op: "now", 1808 }, nil 1809 } 1810 / "tonumber" L_PAREN stringExpr:StringExpr baseExpr:(COMMA NumericExprLevel3)? R_PAREN { 1811 stringExprConverted, ok := stringExpr.(*structs.StringExpr) 1812 if !ok { 1813 return nil, fmt.Errorf("Failed to assert stringExpr as *structs.StringExpr") 1814 } 1815 1816 var baseExprConverted *structs.NumericExpr 1817 if baseExpr != nil { 1818 baseSlice, ok := baseExpr.([]interface{}) 1819 if ok && len(baseSlice) > 1 { 1820 if base, ok := baseSlice[1].(*structs.NumericExpr); ok { 1821 baseExprConverted = base 1822 } else { 1823 return nil, fmt.Errorf("Failed to assert base as *structs.NumericExpr") 1824 } 1825 } 1826 } 1827 1828 node := &structs.NumericExpr { 1829 IsTerminal: false, 1830 Op: "tonumber", 1831 Left: nil, 1832 Right: baseExprConverted, 1833 Val: stringExprConverted, 1834 NumericExprMode: structs.NEMNumericExpr, 1835 } 1836 return node, nil 1837 } 1838 / lenExpr: "len" L_PAREN expr:LenExpr R_PAREN { 1839 return expr, nil 1840 } 1841 1842 LenExpr <- str:QuotedString !(EVAL_CONCAT) { 1843 1844 leftNumericExpr := &structs.NumericExpr{ 1845 IsTerminal: true, 1846 ValueIsField: false, 1847 Value: str.(string), 1848 NumericExprMode: structs.NEMLenString, 1849 } 1850 1851 node, err := createNumericExpr("len", leftNumericExpr, nil, structs.NEMLenString) 1852 if err != nil { 1853 return nil, err 1854 } 1855 1856 return node, nil 1857 } 1858 / field:EvalFieldToRead !(OpPlus / OpMinus / OpMul / OpDiv / EVAL_CONCAT / "(") { 1859 1860 leftNumericExpr := &structs.NumericExpr{ 1861 IsTerminal: true, 1862 ValueIsField: true, 1863 Value: field.(string), 1864 NumericExprMode: structs.NEMLenField, 1865 } 1866 1867 node, err := createNumericExpr("len", leftNumericExpr, nil, structs.NEMLenField) 1868 if err != nil { 1869 return nil, err 1870 } 1871 1872 return node, nil 1873 } 1874 1875 // Returns *structs.QueryAggregators 1876 HeadBlock <- PIPE CMD_HEAD ("limit" EQUAL)? intAsStr:IntegerAsString { 1877 limit, err := strconv.ParseUint(intAsStr.(string), 10, 64) 1878 if err != nil { 1879 return nil, fmt.Errorf("Invalid limit (%v): %v", intAsStr.(string), err) 1880 } 1881 1882 queryAgg := &structs.QueryAggregators { 1883 PipeCommandType: structs.OutputTransformType, 1884 OutputTransforms: &structs.OutputTransforms { 1885 MaxRows: limit, 1886 }, 1887 } 1888 1889 return queryAgg, nil 1890 } 1891 / PIPE CMD_HEAD_NO_SPACE { 1892 queryAgg := &structs.QueryAggregators { 1893 PipeCommandType: structs.OutputTransformType, 1894 OutputTransforms: &structs.OutputTransforms { 1895 MaxRows: uint64(10), // From https://docs.splunk.com/Documentation/Splunk/9.1.0/SearchReference/Head 1896 }, 1897 } 1898 1899 return queryAgg, nil 1900 } 1901 1902 // Parses one or more AggFunctions separated by a comma and space. 1903 // Returns a slice containing all the AggFunctions. 1904 AggregationList <- first:Aggregator rest:((COMMA / SPACE) Aggregator)* { 1905 // Convert `rest` to a slice. Each element of the slice will be a 2-element 1906 // slice where the first element is ", " and the second is an Aggregator. 1907 restSlice := rest.([]any) 1908 1909 numAggs := 1 + len(restSlice) 1910 aggsSlice := make([]*aggregator, numAggs) 1911 aggsSlice[0] = first.(*aggregator) 1912 1913 for i := 1; i < numAggs; i++ { 1914 separatorAndAgg := restSlice[i - 1].([]any) 1915 aggsSlice[i] = separatorAndAgg[1].(*aggregator) 1916 } 1917 1918 return aggsSlice, nil 1919 } 1920 1921 Aggregator <- aggFunc:AggFunction asField:AsField? { 1922 agg := &aggregator{} 1923 agg.measureAgg = aggFunc.(*structs.MeasureAggregator) 1924 1925 if asField != nil { 1926 agg.renameOutputField = true 1927 agg.outputFieldNewName = asField.(string) 1928 } 1929 1930 return agg, nil 1931 } 1932 1933 // For evaluation statements inside aggregate functions: 1934 // 1. min, max, sum, avg, and range can only evaluate boolComparisonExpr, as they need to compute the field value inside the expression. There should be only one field. 1935 // 2. count can evaluate boolExpr because it does not care about the field value inside the expression. It only cares about whether the current row should be counted or not. 1936 // 3. distinctCount and values can evaluate valueExpr because they just need to find out the distinct values of the result of the expression. As for the type of the expression result, it is not important. 1937 AggFunction <- agg:(AggCount / AggDistinctCount / AggAvg / AggMin / AggMax / AggRange / AggSum / AggValues) { 1938 return agg, nil 1939 } 1940 1941 AsField <- AS field: (FieldName / String) { 1942 fieldStr := field.(string) 1943 1944 if strings.Contains(fieldStr, "*") { 1945 return nil, errors.New("The field specified in `AS` cannot contain wildcards") 1946 } 1947 1948 if fieldStr[0] == '"' && fieldStr[len(fieldStr)-1] == '"' { 1949 fieldStr = fieldStr[1 : len(fieldStr)-1] 1950 } 1951 1952 return fieldStr, nil 1953 } 1954 1955 AggCount <- ("count" / "c") L_PAREN "eval" boolExpr:BoolExpr R_PAREN { 1956 valueExpr := &structs.ValueExpr { 1957 ValueExprMode: structs.VEMBooleanExpr, 1958 BooleanExpr: boolExpr.(*structs.BoolExpr), 1959 } 1960 1961 agg := &structs.MeasureAggregator { 1962 MeasureCol: "", 1963 MeasureFunc: utils.Count, 1964 StrEnc: string(c.text), 1965 ValueColRequest: valueExpr, 1966 } 1967 1968 return agg, nil 1969 } 1970 / ("count" / "c") L_PAREN field:FieldName R_PAREN { 1971 agg := &structs.MeasureAggregator { 1972 MeasureCol: field.(string), 1973 MeasureFunc: utils.Count, 1974 } 1975 1976 return agg, nil 1977 } / ("count" / "c") { 1978 agg := &structs.MeasureAggregator { 1979 MeasureCol: "*", 1980 MeasureFunc: utils.Count, 1981 } 1982 1983 return agg, nil 1984 } 1985 1986 AggDistinctCount <- ("distinct_count" / "dc") L_PAREN "eval" valueExpr:ValueExpr R_PAREN { 1987 agg := &structs.MeasureAggregator { 1988 MeasureCol: "", 1989 MeasureFunc: utils.Cardinality, 1990 StrEnc: string(c.text), 1991 ValueColRequest: valueExpr.(*structs.ValueExpr), 1992 } 1993 1994 return agg, nil 1995 } 1996 / ("distinct_count" / "dc") L_PAREN field:FieldName R_PAREN { 1997 agg := &structs.MeasureAggregator { 1998 MeasureCol: field.(string), 1999 MeasureFunc: utils.Cardinality, 2000 } 2001 2002 return agg, nil 2003 } 2004 2005 AggAvg <- "avg" L_PAREN "eval" L_PAREN boolComparisonExpr:BoolComparisonExpr R_PAREN R_PAREN { 2006 valueExpr := &structs.ValueExpr { 2007 ValueExprMode: structs.VEMBooleanExpr, 2008 BooleanExpr: boolComparisonExpr.(*structs.BoolExpr), 2009 } 2010 2011 agg := &structs.MeasureAggregator { 2012 MeasureCol: "", 2013 MeasureFunc: utils.Avg, 2014 StrEnc: string(c.text), 2015 ValueColRequest: valueExpr, 2016 } 2017 2018 return agg, nil 2019 } 2020 / "avg" L_PAREN field:FieldName R_PAREN { 2021 agg := &structs.MeasureAggregator { 2022 MeasureCol: field.(string), 2023 MeasureFunc: utils.Avg, 2024 } 2025 2026 return agg, nil 2027 } 2028 2029 AggMin <- "min" L_PAREN "eval" L_PAREN boolComparisonExpr:BoolComparisonExpr R_PAREN R_PAREN { 2030 valueExpr := &structs.ValueExpr { 2031 ValueExprMode: structs.VEMBooleanExpr, 2032 BooleanExpr: boolComparisonExpr.(*structs.BoolExpr), 2033 } 2034 2035 agg := &structs.MeasureAggregator { 2036 MeasureCol: "", 2037 MeasureFunc: utils.Min, 2038 StrEnc: string(c.text), 2039 ValueColRequest: valueExpr, 2040 } 2041 2042 return agg, nil 2043 } 2044 / "min" L_PAREN field:FieldName R_PAREN { 2045 agg := &structs.MeasureAggregator { 2046 MeasureCol: field.(string), 2047 MeasureFunc: utils.Min, 2048 } 2049 2050 return agg, nil 2051 } 2052 2053 AggMax <- "max" L_PAREN "eval" L_PAREN boolComparisonExpr:BoolComparisonExpr R_PAREN R_PAREN { 2054 valueExpr := &structs.ValueExpr { 2055 ValueExprMode: structs.VEMBooleanExpr, 2056 BooleanExpr: boolComparisonExpr.(*structs.BoolExpr), 2057 } 2058 2059 agg := &structs.MeasureAggregator { 2060 MeasureCol: "", 2061 MeasureFunc: utils.Max, 2062 StrEnc: string(c.text), 2063 ValueColRequest: valueExpr, 2064 } 2065 2066 return agg, nil 2067 } 2068 / "max" L_PAREN field:FieldName R_PAREN { 2069 agg := &structs.MeasureAggregator { 2070 MeasureCol: field.(string), 2071 MeasureFunc: utils.Max, 2072 } 2073 2074 return agg, nil 2075 } 2076 2077 AggRange <- "range" L_PAREN "eval" L_PAREN boolComparisonExpr:BoolComparisonExpr R_PAREN R_PAREN { 2078 valueExpr := &structs.ValueExpr { 2079 ValueExprMode: structs.VEMBooleanExpr, 2080 BooleanExpr: boolComparisonExpr.(*structs.BoolExpr), 2081 } 2082 2083 agg := &structs.MeasureAggregator { 2084 MeasureCol: "", 2085 MeasureFunc: utils.Range, 2086 StrEnc: string(c.text), 2087 ValueColRequest: valueExpr, 2088 } 2089 2090 return agg, nil 2091 } 2092 / "range" L_PAREN field:FieldName R_PAREN { 2093 agg := &structs.MeasureAggregator { 2094 MeasureCol: field.(string), 2095 MeasureFunc: utils.Range, 2096 } 2097 2098 return agg, nil 2099 } 2100 2101 AggSum <- "sum" L_PAREN "eval" L_PAREN boolComparisonExpr:BoolComparisonExpr R_PAREN R_PAREN { 2102 valueExpr := &structs.ValueExpr { 2103 ValueExprMode: structs.VEMBooleanExpr, 2104 BooleanExpr: boolComparisonExpr.(*structs.BoolExpr), 2105 } 2106 2107 agg := &structs.MeasureAggregator { 2108 MeasureCol: "", 2109 MeasureFunc: utils.Sum, 2110 StrEnc: string(c.text), 2111 ValueColRequest: valueExpr, 2112 } 2113 2114 return agg, nil 2115 } 2116 / "sum" L_PAREN field:FieldName R_PAREN { 2117 agg := &structs.MeasureAggregator { 2118 MeasureCol: field.(string), 2119 MeasureFunc: utils.Sum, 2120 } 2121 2122 return agg, nil 2123 } 2124 2125 AggValues <- "values" L_PAREN "eval" valueExpr:ValueExpr R_PAREN { 2126 agg := &structs.MeasureAggregator { 2127 MeasureCol: "", 2128 MeasureFunc: utils.Values, 2129 StrEnc: string(c.text), 2130 ValueColRequest: valueExpr.(*structs.ValueExpr), 2131 } 2132 2133 return agg, nil 2134 } 2135 / "values" L_PAREN field:FieldName R_PAREN { 2136 agg := &structs.MeasureAggregator { 2137 MeasureCol: field.(string), 2138 MeasureFunc: utils.Values, 2139 } 2140 2141 return agg, nil 2142 } 2143 2144 FieldWithNumberValue <- keyValuePair:(NamedFieldWithNumberValue / UnnamedFieldWithNumberValue) { 2145 return keyValuePair, nil 2146 } 2147 2148 NamedFieldWithNumberValue <- key:FieldName op:(EqualityOperator / InequalityOperator) value:Number { 2149 node := &ast.Node{ 2150 NodeType: ast.NodeTerminal, 2151 Comparison:ast.Comparison{ 2152 Op: op.(string), 2153 Field: key.(string), 2154 Values: value, 2155 }, 2156 } 2157 2158 return node, nil 2159 } 2160 2161 UnnamedFieldWithNumberValue <- value:Number { 2162 node := &ast.Node{ 2163 NodeType: ast.NodeTerminal, 2164 Comparison:ast.Comparison{ 2165 Op: "=", 2166 Field: "*", 2167 Values: value, 2168 }, 2169 } 2170 2171 return node, nil 2172 } 2173 2174 FieldWithBooleanValue <- key:FieldName op:EqualityOperator value:Boolean { 2175 node := &ast.Node{ 2176 NodeType: ast.NodeTerminal, 2177 Comparison:ast.Comparison{ 2178 Op: op.(string), 2179 Field: key.(string), 2180 Values: value, 2181 }, 2182 } 2183 2184 return node, nil 2185 } 2186 2187 FieldWithStringValue <- keyValuePair:(NamedFieldWithStringValue / UnnamedFieldWithStringValue) { 2188 return keyValuePair, nil 2189 } 2190 2191 NamedFieldWithStringValue <- key:FieldName op:EqualityOperator value:String { 2192 node := &ast.Node{ 2193 NodeType: ast.NodeTerminal, 2194 Comparison:ast.Comparison{ 2195 Op: op.(string), 2196 Field: key.(string), 2197 Values: value, 2198 }, 2199 } 2200 return node, nil 2201 } 2202 2203 UnnamedFieldWithStringValue <- value:String { 2204 node := &ast.Node{ 2205 NodeType: ast.NodeTerminal, 2206 Comparison:ast.Comparison{ 2207 Op: "=", 2208 Field: "*", 2209 Values: value, 2210 }, 2211 } 2212 return node, nil 2213 } 2214 2215 // Parses one or more FieldNames separated by a comma and space. 2216 // Returns a slice containing all the FieldNames. 2217 FieldNameList <- first:FieldName rest:(COMMA FieldName)* { 2218 // Convert `rest` to a slice. Each element of the slice will be a 2-element 2219 // slice where the first element is ", " and the second is a FieldName. 2220 restSlice := rest.([]any) 2221 2222 numFieldNames := 1 + len(restSlice) 2223 fields := make([]string, numFieldNames) 2224 fields[0] = first.(string) 2225 2226 for i := 1; i < numFieldNames; i++ { 2227 separatorAndField := restSlice[i - 1].([]any) 2228 fields[i] = separatorAndField[1].(string) 2229 } 2230 2231 return fields, nil 2232 } 2233 2234 // From https://docs.splunk.com/Documentation/Splunk/7.3.1/Knowledge/Aboutregularexpressionswithfieldextractions 2235 // This allows wildcards in a FieldName, but wildcard fields are not allowed in 2236 // some places; those rules should check whether the field has a wildcard. 2237 FieldName <- [a-zA-Z0-9:*][a-zA-Z0-9:_.*]* { 2238 return string(c.text), nil 2239 } 2240 2241 String <- str:(QuotedString / UnquotedString) { 2242 return str, nil 2243 } 2244 2245 QuotedString <- '"' [^"]* '"' { 2246 // The returned string has quotes as the first and last character. 2247 return string(c.text), nil 2248 } 2249 2250 Boolean <- ("true" / "false") { 2251 boolValue, _ := strconv.ParseBool(string(c.text)) 2252 return boolValue, nil 2253 } 2254 2255 UnquotedString <- ("*" / (!(MAJOR_BREAK / "|" / EOF) .))+ { 2256 // Return the string wrapped in quotes. 2257 str := "\"" + string(c.text) + "\"" 2258 return str, nil 2259 } 2260 2261 //Can recognize fieldName or Regex Pattern for Rename Block 2262 RenamePattern <- [a-zA-Z0-9_*]+ { 2263 return string(c.text), nil 2264 } 2265 2266 Number <- number:NumberAsString { 2267 return json.Number(number.(string)), nil 2268 } 2269 2270 // If a number isn't followed by a space, ")", comma, or EOF, we probably want 2271 // to fail and parse it as a string instead. 2272 NumberAsString <- number:(FloatAsString / IntegerAsString) &(SPACE / "|" / ")" / "," / EOF) { 2273 return number, nil 2274 } 2275 2276 // Allow leading zeros, a "+" before the number, and a decimal point before 2277 // the first digit. 2278 FloatAsString <- [-+]? [0-9]* "." [0-9]+ { 2279 return string(c.text), nil 2280 } 2281 2282 // Allow leading zeros and a "+" before the number. 2283 IntegerAsString <- [-+]? [0-9]+ { 2284 return string(c.text), nil 2285 } 2286 2287 EqualityOperator <- EMPTY_OR_SPACE op:("=" / "!=") EMPTY_OR_SPACE { 2288 opStr, err := transferUint8ToString(op) 2289 if err != nil { 2290 return nil, fmt.Errorf("Spl peg: EqualityOperator: %v", err) 2291 } 2292 return opStr, nil 2293 } 2294 2295 InequalityOperator <- EMPTY_OR_SPACE op:("<=" / "<" / ">=" / ">") EMPTY_OR_SPACE { 2296 opStr, err := transferUint8ToString(op) 2297 if err != nil { 2298 return nil, fmt.Errorf("Spl peg: InequalityOperator: %v", err) 2299 } 2300 return opStr, nil 2301 } 2302 2303 EqualityOrInequality <- op:EqualityOperator { 2304 return op, nil 2305 } 2306 / op:InequalityOperator { 2307 return op, nil 2308 } 2309 2310 OpPlus <- EMPTY_OR_SPACE "+" EMPTY_OR_SPACE { 2311 return "+", nil 2312 } 2313 2314 OpMinus <- EMPTY_OR_SPACE "-" EMPTY_OR_SPACE { 2315 return "-", nil 2316 } 2317 2318 OpMul <- EMPTY_OR_SPACE "*" EMPTY_OR_SPACE { 2319 return "*", nil 2320 } 2321 2322 OpDiv <- EMPTY_OR_SPACE "/" EMPTY_OR_SPACE { 2323 return "/", nil 2324 } 2325 2326 // Add Empty space here 2327 Second <- ("seconds" / "second" / "secs" / "sec" / "s") { 2328 return utils.TMSecond, nil 2329 } 2330 2331 Minute <- ("minutes" / "minute" / "mins" / "min" / "m") { 2332 return utils.TMMinute, nil 2333 } 2334 2335 Hour <- ("hours" / "hour" / "hrs" / "hr" / "h") { 2336 return utils.TMHour, nil 2337 } 2338 2339 Day <- ("days" / "day" / "d") { 2340 return utils.TMDay, nil 2341 } 2342 2343 Week <- ("weeks" / "week" / "w") { 2344 return utils.TMWeek, nil 2345 } 2346 2347 Month <- ("months" / "month" / "mon") { 2348 return utils.TMMonth, nil 2349 } 2350 2351 Quarter <- ("quarters" / "quarter" / "qtrs" / "qtr" / "q") { 2352 return utils.TMQuarter, nil 2353 } 2354 2355 // Might not has effect for 'us', because smallest time unit for timestamp in siglens is ms 2356 Subseconds <- ("us" / "ms" / "cs" / "ds") { 2357 timeUnit, err := utils.ConvertSubseconds(string(c.text)) 2358 if err != nil { 2359 return nil, fmt.Errorf("Spl peg: Subseconds: %v", err) 2360 } 2361 return timeUnit, nil 2362 } 2363 2364 // Returns *structs.QueryAggregators 2365 TransactionBlock <- PIPE CMD_TRANSACTION txnOptions:TransactionOptions { 2366 queryAgg := &structs.QueryAggregators{ 2367 PipeCommandType: structs.TransactionType, 2368 TransactionArguments: txnOptions.(*structs.TransactionArguments), 2369 } 2370 return queryAgg, nil 2371 } 2372 2373 // The TransactionDefinitionOptionsList will consist of all the Transaction Options 2374 TransactionOptions <- txnOptions:TransactionDefinitionOptionsList? { 2375 2376 transactionRequest := &structs.TransactionArguments{} 2377 2378 if txnOptions != nil { 2379 txnArgs := txnOptions.(*TxnArgs).arguments 2380 transactionRequest.Fields = txnArgs.Fields 2381 transactionRequest.StartsWith = txnArgs.StartsWith 2382 transactionRequest.EndsWith = txnArgs.EndsWith 2383 } 2384 2385 return transactionRequest, nil 2386 } 2387 2388 2389 TransactionDefinitionOptionsList <- first:TransactionDefinitionOption rest:(SPACE TransactionDefinitionOption)* { 2390 2391 restSlice := rest.([]any) 2392 txnArgs := &TxnArgs{ 2393 argOption: "txn-definition", 2394 arguments: &structs.TransactionArguments{}, 2395 } 2396 2397 numArgs := 1 + len(restSlice) 2398 2399 for i := 0; i < numArgs; i++ { 2400 var txnArg *TxnArgs 2401 if i == 0 { 2402 txnArg = first.(*TxnArgs) 2403 } else { 2404 separatorAndArg := restSlice[i - 1].([]any) 2405 txnArg = separatorAndArg[1].(*TxnArgs) 2406 } 2407 argOption := txnArg.argOption 2408 2409 switch argOption { 2410 case "fields": 2411 txnArgs.arguments.Fields = txnArg.arguments.Fields 2412 case "startswith": 2413 txnArgs.arguments.StartsWith = txnArg.arguments.StartsWith 2414 case "endswith": 2415 txnArgs.arguments.EndsWith = txnArg.arguments.EndsWith 2416 default: 2417 return nil, fmt.Errorf("Not a Valid Transaction Argument option") 2418 } 2419 } 2420 2421 return txnArgs, nil 2422 } 2423 2424 TransactionDefinitionOption <- option:(SpaceSeparatedFieldNameList / StartsWithOption / EndsWithOption) { 2425 return option, nil 2426 } 2427 2428 // Parses one or more FieldNames separate by a space 2429 // Returns a slice containing all the FieldNames 2430 SpaceSeparatedFieldNameList <- first:FieldName !(EQUAL) rest:(SPACE FieldName !(EQUAL))* { 2431 var fields []string 2432 fields = append(fields, first.(string)) 2433 for _, r := range rest.([]any) { 2434 // Extracting the field name from the tuple (SPACE, FieldName) 2435 fields = append(fields, r.([]any)[1].(string)) 2436 } 2437 2438 txnArg := &TxnArgs{ 2439 argOption: "fields", 2440 arguments: &structs.TransactionArguments{ 2441 Fields: fields, 2442 }, 2443 } 2444 2445 return txnArg, nil 2446 } 2447 2448 StartsWithOption <- "startswith" EQUAL strExpr:TransactionFilterString { 2449 txnArg := &TxnArgs{ 2450 argOption: "startswith", 2451 arguments: &structs.TransactionArguments{ 2452 StartsWith: strExpr.(*structs.FilterStringExpr), 2453 }, 2454 } 2455 return txnArg, nil 2456 } 2457 2458 EndsWithOption <- "endswith" EQUAL strExpr:TransactionFilterString { 2459 txnArg := &TxnArgs{ 2460 argOption: "endswith", 2461 arguments: &structs.TransactionArguments{ 2462 EndsWith: strExpr.(*structs.FilterStringExpr), 2463 }, 2464 } 2465 return txnArg, nil 2466 } 2467 2468 // Returns structs.FilterStringExpr 2469 TransactionFilterString <- strExpr:(TransactionQuotedString / TransactionEval / TransactionSearch) { 2470 return strExpr, nil 2471 } 2472 2473 TransactionQuotedString <- str:(TransactionQuotedStringValue / TransactionQuotedStringSearchExpr) { 2474 return str, nil 2475 } 2476 2477 TransactionQuotedStringSearchExpr <- '"' searchClause:ClauseLevel4 '"' { 2478 filterStrExpr := &structs.FilterStringExpr{ 2479 SearchNode: searchClause.(*ast.Node), 2480 } 2481 2482 return filterStrExpr, nil 2483 } 2484 2485 QuotedStringNoOp <- '"' [^" !(OR / AND)]* '"' { 2486 // The returned string has quotes as the first and last character. 2487 return string(c.text), nil 2488 } 2489 2490 TransactionQuotedStringValue <- str:QuotedStringNoOp { 2491 filterStrExpr := &structs.FilterStringExpr{ 2492 StringValue: removeQuotes(str.(string)), 2493 } 2494 2495 return filterStrExpr, nil 2496 } 2497 2498 TransactionSearch <- expr:ClauseLevel1 { 2499 2500 filterStrExpr := &structs.FilterStringExpr{ 2501 SearchNode: expr.(*ast.Node), 2502 } 2503 2504 return filterStrExpr, nil 2505 } 2506 2507 // eval(<bool-expression>) 2508 TransactionEval <- "eval" EMPTY_OR_SPACE L_PAREN condition:BoolExpr R_PAREN { 2509 filterStrExpr := &structs.FilterStringExpr{ 2510 EvalBoolExpr: condition.(*structs.BoolExpr), 2511 } 2512 2513 return filterStrExpr, nil 2514 } 2515 2516 2517 // All cmd expect CMD_SEARCH 2518 ALLCMD <- (CMD_REGEX / CMD_STATS / CMD_FIELDS / CMD_WHERE / CMD_HEAD_NO_SPACE / CMD_HEAD / CMD_EVAL / CMD_REX / CMD_TOP / CMD_RARE / CMD_RENAME / CMD_TIMECHART / CMD_TRANSACTION / CMD_DEDUP / CMD_SORT) 2519 CMD_SEARCH <- "search" SPACE 2520 CMD_REGEX <- "regex" SPACE 2521 CMD_STATS <- "stats" SPACE 2522 CMD_FIELDS <- "fields" SPACE 2523 CMD_WHERE <- "where" SPACE 2524 CMD_HEAD_NO_SPACE <- "head" 2525 CMD_HEAD <- CMD_HEAD_NO_SPACE SPACE 2526 CMD_EVAL <- "eval" SPACE 2527 CMD_REX <- "rex" SPACE 2528 CMD_SORT <- "sort" SPACE 2529 CMD_TOP <- "top" 2530 CMD_RARE <- "rare" 2531 CMD_RENAME <- "rename" SPACE 2532 CMD_TIMECHART <- "timechart" SPACE 2533 CMD_SPAN <- "span" 2534 CMD_TRANSACTION <- "transaction" SPACE 2535 CMD_DEDUP <- "dedup" 2536 CMD_DEDUP_SORTBY <- SPACE "sortby" SPACE 2537 EVAL_CONCAT <- SPACE? "." SPACE? 2538 2539 // Major and Minor breaks from https://docs.splunk.com/Documentation/Splunk/9.0.4/Admin/Segmentersconf 2540 MAJOR_BREAK <- [[\]<>(){}|!;,'"*\n\r \t&?+] / "%21" / "%26" / 2541 "%2526" / "%3B" / "%7C" / "%20" / "%2B" / "%3D" / "--" / 2542 "%2520" / "%5D" / "%5B" / "%3A" / "%0A" / "%2C" / "%28" / "%29" 2543 MINOR_BREAK <- [/:=@.$#%_] / "-" / "\\" 2544 2545 // https://community.splunk.com/t5/Splunk-Search/are-search-language-keywords-case-sensitive/m-p/9106 2546 // has some information about case sensitivity. 2547 NOT <- "NOT" SPACE 2548 OR <- SPACE "OR" SPACE 2549 AND <- SPACE "AND" SPACE 2550 PIPE <- EMPTY_OR_SPACE "|" EMPTY_OR_SPACE 2551 AS <- SPACE "AS"i SPACE // Case insensitive 2552 BY <- SPACE "BY"i SPACE // Case insensitive 2553 2554 EQUAL <- EMPTY_OR_SPACE "=" EMPTY_OR_SPACE 2555 COMMA <- EMPTY_OR_SPACE "," EMPTY_OR_SPACE 2556 L_PAREN <- "(" EMPTY_OR_SPACE 2557 R_PAREN <- EMPTY_OR_SPACE ")" 2558 2559 EOF <- !. 2560 SPACE <- (" "? COMMENT " "?) / " "+ 2561 COMMENT <- "```" (!("```") .)* "```" 2562 EMPTY_OR_SPACE <- SPACE / "" 2563 EMPTY_OR_COMMA <- COMMA / EMPTY_OR_SPACE