@@ -313,6 +313,53 @@ class MetricSpec(TypedDict):
313
313
tags : NotRequired [Sequence [TagSpec ]]
314
314
315
315
316
+ def _transform_search_filter (search_filter : SearchFilter ) -> SearchFilter :
317
+ # If we have `message:something` we convert it to `message:*something*` since we want to perform `contains` matching
318
+ # exactly how discover does it.
319
+ if search_filter .key .name == "message" :
320
+ return SearchFilter (
321
+ key = SearchKey (name = search_filter .key .name ),
322
+ operator = search_filter .operator ,
323
+ value = SearchValue (raw_value = f"*{ search_filter .value .raw_value } *" ),
324
+ )
325
+
326
+ # If we have `transaction.status:unknown_error` we convert it to `transaction.status:unknown` since we need to be
327
+ # backward compatible.
328
+ if (
329
+ search_filter .key .name == "transaction.status"
330
+ and search_filter .value .raw_value == "unknown_error"
331
+ ):
332
+ return SearchFilter (
333
+ key = SearchKey (name = search_filter .key .name ),
334
+ operator = search_filter .operator ,
335
+ value = SearchValue (raw_value = "unknown" ),
336
+ )
337
+
338
+ return search_filter
339
+
340
+
341
+ def _transform_search_query (query : Sequence [QueryToken ]) -> Sequence [QueryToken ]:
342
+ transformed_query : List [QueryToken ] = []
343
+
344
+ for token in query :
345
+ if isinstance (token , SearchFilter ):
346
+ transformed_query .append (_transform_search_filter (token ))
347
+ elif isinstance (token , ParenExpression ):
348
+ transformed_query .append (ParenExpression (_transform_search_query (token .children )))
349
+ else :
350
+ transformed_query .append (token )
351
+
352
+ return transformed_query
353
+
354
+
355
+ def _parse_search_query (query : Optional [str ]) -> Sequence [QueryToken ]:
356
+ """
357
+ Parses a search query with the discover grammar and performs some transformations on the AST in order to account for
358
+ edge cases.
359
+ """
360
+ return _transform_search_query (event_search .parse_search_query (query ))
361
+
362
+
316
363
@dataclass (frozen = True )
317
364
class SupportedBy :
318
365
"""Result of a check for standard and on-demand metric support."""
@@ -457,7 +504,7 @@ def _get_groupbys_support(groupbys: Sequence[str]) -> SupportedBy:
457
504
458
505
def _get_query_supported_by (query : Optional [str ]) -> SupportedBy :
459
506
try :
460
- parsed_query = event_search . parse_search_query (query )
507
+ parsed_query = _parse_search_query (query )
461
508
462
509
standard_metrics = _is_standard_metrics_query (parsed_query )
463
510
on_demand_metrics = _is_on_demand_supported_query (parsed_query )
@@ -575,7 +622,7 @@ def to_standard_metrics_query(query: str) -> str:
575
622
"transaction.duration:>=1s AND browser.version:1" -> ""
576
623
"""
577
624
try :
578
- tokens = event_search . parse_search_query (query )
625
+ tokens = _parse_search_query (query )
579
626
except InvalidSearchQuery :
580
627
logger .error (f"Failed to parse search query: { query } " , exc_info = True )
581
628
raise
@@ -1153,7 +1200,7 @@ def _parse_field(value: str) -> FieldParsingResult:
1153
1200
def _parse_query (value : str ) -> QueryParsingResult :
1154
1201
"""Parse query string into our internal AST format."""
1155
1202
try :
1156
- conditions = event_search . parse_search_query (value )
1203
+ conditions = _parse_search_query (value )
1157
1204
clean_conditions = cleanup_query (_remove_event_type_and_project_filter (conditions ))
1158
1205
return QueryParsingResult (conditions = clean_conditions )
1159
1206
except InvalidSearchQuery as e :
@@ -1327,15 +1374,6 @@ def _filter(self, token: SearchFilter) -> RuleCondition:
1327
1374
if not operator :
1328
1375
raise ValueError (f"Unsupported operator { token .operator } " )
1329
1376
1330
- # If we have a `message` field, we want to convert it to a glob matching, since in the UI `message` will perform
1331
- # a contains style match.
1332
- if token .key .name == "message" :
1333
- token = SearchFilter (
1334
- key = SearchKey (name = token .key .name ),
1335
- operator = token .operator ,
1336
- value = SearchValue (raw_value = f"*{ token .value .raw_value } *" ),
1337
- )
1338
-
1339
1377
# We propagate the filter in order to give as output a better error message with more context.
1340
1378
key : str = token .key .name
1341
1379
value : Any = token .value .raw_value
0 commit comments