82
82
"http.method" : "request.method" ,
83
83
"http.url" : "request.url" ,
84
84
"http.referer" : "request.headers.Referer" ,
85
+ "transaction.source" : "transaction.source" ,
85
86
# url is a tag extracted by Sentry itself, on Relay it's received as `request.url`
86
87
"url" : "request.url" ,
87
88
"sdk.name" : "sdk.name" ,
238
239
"browser.name" ,
239
240
"os.name" ,
240
241
"geo.country_code" ,
241
- # These are skipped during on demand spec generation and will not be converted to metric extraction conditions
242
- "event.type" ,
243
- "project" ,
244
242
]
245
243
244
+ # Query fields that we do not consider for the extraction since they are not needed.
245
+ _BLACKLISTED_METRIC_FIELDS = ["event.type" , "project" ]
246
+
246
247
# Operators used in ``ComparingRuleCondition``.
247
248
CompareOp = Literal ["eq" , "gt" , "gte" , "lt" , "lte" , "glob" ]
248
249
@@ -356,12 +357,22 @@ def _transform_search_query(query: Sequence[QueryToken]) -> Sequence[QueryToken]
356
357
return transformed_query
357
358
358
359
359
- def _parse_search_query (query : Optional [str ]) -> Sequence [QueryToken ]:
360
+ def _parse_search_query (
361
+ query : Optional [str ], removed_blacklisted : bool = False
362
+ ) -> Sequence [QueryToken ]:
360
363
"""
361
364
Parses a search query with the discover grammar and performs some transformations on the AST in order to account for
362
365
edge cases.
363
366
"""
364
- return _transform_search_query (event_search .parse_search_query (query ))
367
+ tokens = cast (Sequence [QueryToken ], event_search .parse_search_query (query ))
368
+ # As first step, we transform the search query by applying basic transformations.
369
+ tokens = _transform_search_query (tokens )
370
+
371
+ # As second step, if enabled, we remove elements from the query which are blacklisted.
372
+ if removed_blacklisted :
373
+ tokens = _cleanup_query (_remove_blacklisted_search_filters (tokens ))
374
+
375
+ return tokens
365
376
366
377
367
378
@dataclass (frozen = True )
@@ -528,7 +539,7 @@ def _get_groupbys_support(groupbys: Sequence[str]) -> SupportedBy:
528
539
529
540
def _get_query_supported_by (query : Optional [str ]) -> SupportedBy :
530
541
try :
531
- parsed_query = _parse_search_query (query )
542
+ parsed_query = _parse_search_query (query = query , removed_blacklisted = False )
532
543
533
544
standard_metrics = _is_standard_metrics_query (parsed_query )
534
545
on_demand_metrics = _is_on_demand_supported_query (parsed_query )
@@ -543,7 +554,6 @@ def _is_standard_metrics_query(tokens: Sequence[QueryToken]) -> bool:
543
554
"""
544
555
Recursively checks if any of the supplied token contain search filters that can't be handled by standard metrics.
545
556
"""
546
-
547
557
for token in tokens :
548
558
if not _is_standard_metrics_search_filter (token ):
549
559
return False
@@ -565,7 +575,6 @@ def _is_on_demand_supported_query(tokens: Sequence[QueryToken]) -> bool:
565
575
"""
566
576
Recursively checks if any of the supplied token contain search filters that can't be handled by standard metrics.
567
577
"""
568
-
569
578
for token in tokens :
570
579
if not _is_on_demand_supported_search_filter (token ):
571
580
return False
@@ -621,6 +630,10 @@ def _is_standard_metrics_search_term(field: str) -> bool:
621
630
622
631
623
632
def _is_on_demand_supported_field (field : str ) -> bool :
633
+ # If it's a black listed field, we consider it as compatible with on demand.
634
+ if field in _BLACKLISTED_METRIC_FIELDS :
635
+ return True
636
+
624
637
try :
625
638
_map_field_name (field )
626
639
return True
@@ -646,7 +659,7 @@ def to_standard_metrics_query(query: str) -> str:
646
659
"transaction.duration:>=1s AND browser.version:1" -> ""
647
660
"""
648
661
try :
649
- tokens = _parse_search_query (query )
662
+ tokens = _parse_search_query (query = query , removed_blacklisted = False )
650
663
except InvalidSearchQuery :
651
664
logger .exception ("Failed to parse search query: %s" , query )
652
665
raise
@@ -661,7 +674,7 @@ def to_standard_metrics_tokens(tokens: Sequence[QueryToken]) -> Sequence[QueryTo
661
674
that has all on-demand filters removed and can be run using only standard metrics.
662
675
"""
663
676
remaining_tokens = _remove_on_demand_search_filters (tokens )
664
- cleaned_query = cleanup_query (remaining_tokens )
677
+ cleaned_query = _cleanup_query (remaining_tokens )
665
678
return cleaned_query
666
679
667
680
@@ -680,7 +693,7 @@ def query_tokens_to_string(tokens: Sequence[QueryToken]) -> str:
680
693
681
694
def _remove_on_demand_search_filters (tokens : Sequence [QueryToken ]) -> Sequence [QueryToken ]:
682
695
"""
683
- removes tokens that contain filters that can only be handled by on demand metrics.
696
+ Removes tokens that contain filters that can only be handled by on demand metrics.
684
697
"""
685
698
ret_val : List [QueryToken ] = []
686
699
for token in tokens :
@@ -691,26 +704,28 @@ def _remove_on_demand_search_filters(tokens: Sequence[QueryToken]) -> Sequence[Q
691
704
ret_val .append (ParenExpression (_remove_on_demand_search_filters (token .children )))
692
705
else :
693
706
ret_val .append (token )
707
+
694
708
return ret_val
695
709
696
710
697
- def _remove_event_type_and_project_filter (tokens : Sequence [QueryToken ]) -> Sequence [QueryToken ]:
711
+ def _remove_blacklisted_search_filters (tokens : Sequence [QueryToken ]) -> Sequence [QueryToken ]:
698
712
"""
699
- removes event.type: transaction and project:* from the query
713
+ Removes tokens that contain filters that are blacklisted.
700
714
"""
701
715
ret_val : List [QueryToken ] = []
702
716
for token in tokens :
703
717
if isinstance (token , SearchFilter ):
704
- if token .key .name not in [ "event.type" , "project" ] :
718
+ if token .key .name not in _BLACKLISTED_METRIC_FIELDS :
705
719
ret_val .append (token )
706
720
elif isinstance (token , ParenExpression ):
707
- ret_val .append (ParenExpression (_remove_event_type_and_project_filter (token .children )))
721
+ ret_val .append (ParenExpression (_remove_blacklisted_search_filters (token .children )))
708
722
else :
709
723
ret_val .append (token )
724
+
710
725
return ret_val
711
726
712
727
713
- def cleanup_query (tokens : Sequence [QueryToken ]) -> Sequence [QueryToken ]:
728
+ def _cleanup_query (tokens : Sequence [QueryToken ]) -> Sequence [QueryToken ]:
714
729
"""
715
730
Recreates a valid query from an original query that has had on demand search filters removed.
716
731
@@ -729,9 +744,10 @@ def cleanup_query(tokens: Sequence[QueryToken]) -> Sequence[QueryToken]:
729
744
if not isinstance (token , ParenExpression ):
730
745
removed_empty_parens .append (token )
731
746
else :
732
- children = cleanup_query (token .children )
747
+ children = _cleanup_query (token .children )
733
748
if len (children ) > 0 :
734
749
removed_empty_parens .append (ParenExpression (children ))
750
+
735
751
# remove AND and OR operators at the start of the query
736
752
while len (removed_empty_parens ) > 0 and isinstance (removed_empty_parens [0 ], str ):
737
753
removed_empty_parens .pop (0 )
@@ -761,6 +777,7 @@ def cleanup_query(tokens: Sequence[QueryToken]) -> Sequence[QueryToken]:
761
777
elif previous_token is not None :
762
778
ret_val .append (previous_token )
763
779
previous_token = token
780
+
764
781
# take care of the last token (if any)
765
782
if previous_token is not None :
766
783
ret_val .append (previous_token )
@@ -1249,9 +1266,8 @@ def _parse_field(value: str) -> FieldParsingResult:
1249
1266
def _parse_query (value : str ) -> QueryParsingResult :
1250
1267
"""Parse query string into our internal AST format."""
1251
1268
try :
1252
- conditions = _parse_search_query (value )
1253
- clean_conditions = cleanup_query (_remove_event_type_and_project_filter (conditions ))
1254
- return QueryParsingResult (conditions = clean_conditions )
1269
+ conditions = _parse_search_query (query = value , removed_blacklisted = True )
1270
+ return QueryParsingResult (conditions = conditions )
1255
1271
except InvalidSearchQuery as e :
1256
1272
raise Exception (f"Invalid search query '{ value } ' in on demand spec: { e } " )
1257
1273
0 commit comments