Skip to content

Commit 216093e

Browse files
authored
feat(metric-issues): Add threshold to metric issue title (#86301)
Specify the threshold if possible for the metric issue title string
1 parent a990ab1 commit 216093e

File tree

2 files changed

+41
-19
lines changed

2 files changed

+41
-19
lines changed

src/sentry/incidents/utils/metric_issue_poc.py

+35-13
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
from django.utils.translation import gettext as _
77

88
from sentry import features
9-
from sentry.incidents.models.alert_rule import AlertRule, AlertRuleThresholdType
10-
from sentry.incidents.models.incident import Incident, IncidentStatus
9+
from sentry.constants import CRASH_RATE_ALERT_AGGREGATE_ALIAS
10+
from sentry.incidents.models.alert_rule import AlertRule, AlertRuleThresholdType, AlertRuleTrigger
11+
from sentry.incidents.models.incident import INCIDENT_STATUS, Incident, IncidentStatus
1112
from sentry.incidents.utils.format_duration import format_duration_idiomatic
1213
from sentry.integrations.metric_alerts import TEXT_COMPARISON_DELTA
1314
from sentry.issues.grouptype import MetricIssuePOC
@@ -43,16 +44,21 @@ def to_dict(self) -> dict[str, Any]:
4344
"count_unique(tags[sentry:user])": "Number of users affected",
4445
"percentage(sessions_crashed, sessions)": "Crash free session rate",
4546
"percentage(users_crashed, users)": "Crash free user rate",
47+
"failure_rate()": "Failure rate",
48+
"apdex()": "Apdex score",
4649
}
4750

4851

49-
def construct_title(alert_rule: AlertRule) -> str:
52+
def construct_title(alert_rule: AlertRule, status: int) -> str:
5053
# Parse the aggregate key from the alert rule
5154
agg_display_key = alert_rule.snuba_query.aggregate
5255
if is_mri_field(agg_display_key):
53-
agg_text = format_mri_field(agg_display_key)
56+
aggregate = format_mri_field(agg_display_key)
57+
elif CRASH_RATE_ALERT_AGGREGATE_ALIAS in agg_display_key:
58+
agg_display_key = agg_display_key.split(f"AS {CRASH_RATE_ALERT_AGGREGATE_ALIAS}")[0].strip()
59+
aggregate = QUERY_AGGREGATION_DISPLAY.get(agg_display_key, agg_display_key)
5460
else:
55-
agg_text = QUERY_AGGREGATION_DISPLAY.get(agg_display_key, alert_rule.snuba_query.aggregate)
61+
aggregate = QUERY_AGGREGATION_DISPLAY.get(agg_display_key, alert_rule.snuba_query.aggregate)
5662

5763
# Determine the higher or lower comparison
5864
higher_or_lower = ""
@@ -61,19 +67,35 @@ def construct_title(alert_rule: AlertRule) -> str:
6167
else:
6268
higher_or_lower = "less than" if alert_rule.comparison_delta else "below"
6369

70+
label = INCIDENT_STATUS[IncidentStatus(status)]
71+
6472
# Format the time window for the threshold
65-
time_window = alert_rule.snuba_query.time_window // 60
66-
title = f"{agg_text} in the last {format_duration_idiomatic(time_window)} {higher_or_lower}"
73+
time_window = format_duration_idiomatic(alert_rule.snuba_query.time_window // 60)
6774

6875
# If the alert rule has a comparison delta, format the comparison string
76+
comparison: str | int | float = "threshold"
6977
if alert_rule.comparison_delta:
7078
comparison_delta_minutes = alert_rule.comparison_delta // 60
71-
comparison_string = TEXT_COMPARISON_DELTA.get(
72-
comparison_delta_minutes, f"same time {comparison_delta_minutes} minutes ago"
79+
comparison = TEXT_COMPARISON_DELTA.get(
80+
comparison_delta_minutes, f"same time {comparison_delta_minutes} minutes ago "
7381
)
74-
return _(f"{title} {comparison_string}")
75-
76-
return _(f"{title} threshold")
82+
else:
83+
# Otherwise, check if there is a trigger with a threshold
84+
trigger = AlertRuleTrigger.objects.filter(id=alert_rule.id, label=label.lower()).first()
85+
if trigger:
86+
threshold = trigger.alert_threshold
87+
comparison = int(threshold) if threshold % 1 == 0 else threshold
88+
89+
template = "{label}: {metric} in the last {time_window} {higher_or_lower} {comparison}"
90+
return _(
91+
template.format(
92+
label=label.capitalize(),
93+
metric=aggregate,
94+
higher_or_lower=higher_or_lower,
95+
comparison=comparison,
96+
time_window=time_window,
97+
)
98+
)
7799

78100

79101
def _build_occurrence_from_incident(
@@ -88,7 +110,7 @@ def _build_occurrence_from_incident(
88110
else PriorityLevel.MEDIUM
89111
)
90112
fingerprint = [str(incident.alert_rule.id)]
91-
title = construct_title(incident.alert_rule)
113+
title = construct_title(incident.alert_rule, incident.status)
92114
return IssueOccurrence(
93115
id=uuid4().hex,
94116
project_id=project.id,

tests/sentry/incidents/utils/test_metric_issue_poc.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ def test_resolved_incident(self):
9191
assert group.priority == PriorityLevel.MEDIUM
9292

9393
def test_construct_title(self):
94-
title = construct_title(self.alert_rule)
95-
assert title == "Number of events in the last 10 minutes above threshold"
94+
title = construct_title(self.alert_rule, self.incident.status)
95+
assert title == "Critical: Number of events in the last 10 minutes above threshold"
9696

9797
alert_rule = self.create_alert_rule(
9898
organization=self.organization,
@@ -105,10 +105,10 @@ def test_construct_title(self):
105105
comparison_delta=60,
106106
)
107107

108-
title = construct_title(alert_rule)
108+
title = construct_title(alert_rule, self.incident.status)
109109
assert (
110110
title
111-
== "Number of users affected in the last 10 minutes greater than same time one hour ago"
111+
== "Critical: Number of users affected in the last 10 minutes greater than same time one hour ago"
112112
)
113113

114114
alert_rule = self.create_alert_rule(
@@ -121,5 +121,5 @@ def test_construct_title(self):
121121
threshold_type=AlertRuleThresholdType.BELOW,
122122
)
123123

124-
title = construct_title(alert_rule)
125-
assert title == "Crash free session rate in the last 10 minutes below threshold"
124+
title = construct_title(alert_rule, 10)
125+
assert title == "Warning: Crash free session rate in the last 10 minutes below threshold"

0 commit comments

Comments
 (0)