Skip to content

Commit 4cb8aa6

Browse files
author
Riccardo Busetti
authored
fix(metrics): Add transformation of transaction status unknown_error to unknown (#59779)
1 parent 058bd85 commit 4cb8aa6

File tree

4 files changed

+96
-1
lines changed

4 files changed

+96
-1
lines changed

src/sentry/search/events/datasets/metrics.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def search_filter_converter(
3232
constants.TEAM_KEY_TRANSACTION_ALIAS: self._key_transaction_filter_converter,
3333
"environment": self.builder._environment_filter_converter,
3434
"transaction": self._transaction_filter_converter,
35+
"transaction.status": self._transaction_status_converter,
3536
"tags[transaction]": self._transaction_filter_converter,
3637
constants.TITLE_ALIAS: self._transaction_filter_converter,
3738
constants.RELEASE_ALIAS: self._release_filter_converter,
@@ -891,6 +892,26 @@ def _transaction_filter_converter(self, search_filter: SearchFilter) -> Optional
891892

892893
return Condition(self.builder.resolve_column("transaction"), Op(operator), value)
893894

895+
def _transaction_status_converter(self, search_filter: SearchFilter) -> Optional[WhereType]:
896+
operator = search_filter.operator
897+
value = search_filter.value.value
898+
899+
# For backward compatibility, `unknown_error` is converted to `unknown`, since Relay always emits `unknown`
900+
# `transaction.status`.
901+
if value == "unknown_error":
902+
value = "unknown"
903+
904+
lhs = self.builder.resolve_column("transaction.status")
905+
906+
if search_filter.value.is_wildcard():
907+
return Condition(
908+
Function("match", [lhs, f"(?i){value}"]),
909+
Op(operator),
910+
1,
911+
)
912+
913+
return Condition(lhs, Op(operator), value)
914+
894915
# Query Functions
895916
def _resolve_count_if(
896917
self,

src/sentry/snuba/metrics/query_builder.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,20 @@ def transform_null_transaction_to_unparameterized(use_case_id, org_id, alias=Non
166166
)
167167

168168

169+
def _refers_to_column(expression: Union[Column, Function]) -> Optional[str]:
170+
"""
171+
Tries to compute to which column the input expression is referring to.
172+
"""
173+
174+
if isinstance(expression, Column):
175+
return expression.name
176+
elif isinstance(expression, Function):
177+
if expression.function == "ifNull":
178+
return expression.parameters[0].name
179+
180+
return None
181+
182+
169183
# Allow these snuba functions.
170184
# These are only allowed because the parser in metrics_sessions_v2
171185
# generates them. Long term we should not allow any functions, but rather
@@ -330,6 +344,16 @@ def resolve_tags(
330344
op=op,
331345
rhs=rhs_ids,
332346
)
347+
348+
# Hacky way to apply a transformation for backward compatibility, which converts `unknown_error` to `unknown`
349+
# for metrics queries.
350+
transformed_rhs = input_.rhs
351+
if (
352+
_refers_to_column(input_.lhs) == "tags[transaction.status]"
353+
and input_.rhs == "unknown_error"
354+
):
355+
transformed_rhs = "unknown"
356+
333357
return Condition(
334358
lhs=resolve_tags(
335359
use_case_id, org_id, input_.lhs, projects, allowed_tag_keys=allowed_tag_keys
@@ -338,7 +362,7 @@ def resolve_tags(
338362
rhs=resolve_tags(
339363
use_case_id,
340364
org_id,
341-
input_.rhs,
365+
transformed_rhs,
342366
projects,
343367
is_tag_value=True,
344368
allowed_tag_keys=allowed_tag_keys,

tests/sentry/api/endpoints/test_organization_metric_data.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,6 +1567,31 @@ def test_include_series(self):
15671567
)
15681568
assert response.status_code == 400
15691569

1570+
def test_transaction_status_unknown_error(self):
1571+
self.store_performance_metric(
1572+
name=TransactionMRI.DURATION.value,
1573+
tags={"transaction.status": "unknown"},
1574+
value=10.0,
1575+
)
1576+
1577+
response = self.get_success_response(
1578+
self.organization.slug,
1579+
field=f"sum({TransactionMetricKey.DURATION.value})",
1580+
query="transaction.status:unknown_error",
1581+
statsPeriod="1h",
1582+
interval="1h",
1583+
per_page=1,
1584+
useCase="transactions",
1585+
)
1586+
groups = response.data["groups"]
1587+
assert groups == [
1588+
{
1589+
"by": {},
1590+
"series": {"sum(transaction.duration)": [10.0]},
1591+
"totals": {"sum(transaction.duration)": 10.0},
1592+
}
1593+
]
1594+
15701595
def test_gauges(self):
15711596
mri = "g:custom/page_load@millisecond"
15721597

tests/snuba/api/endpoints/test_organization_events_stats_mep.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,31 @@ def test_title_filter(self):
564564
[{"count": 0}],
565565
]
566566

567+
def test_transaction_status_unknown_error(self):
568+
self.store_transaction_metric(
569+
123,
570+
tags={"transaction.status": "unknown"},
571+
timestamp=self.day_ago + timedelta(minutes=30),
572+
)
573+
response = self.do_request(
574+
data={
575+
"start": iso_format(self.day_ago),
576+
"end": iso_format(self.day_ago + timedelta(hours=2)),
577+
"interval": "1h",
578+
"query": "transaction.status:unknown_error",
579+
"yAxis": [
580+
"sum(transaction.duration)",
581+
],
582+
"dataset": "metricsEnhanced",
583+
},
584+
)
585+
assert response.status_code == 200, response.content
586+
data = response.data["data"]
587+
assert [attrs for time, attrs in data] == [
588+
[{"count": 123}],
589+
[{"count": 0}],
590+
]
591+
567592
def test_custom_performance_metric_meta_contains_field_and_unit_data(self):
568593
self.store_transaction_metric(
569594
123,

0 commit comments

Comments
 (0)