|
@@ -55,7 +55,7 @@ from sentry.services.hybrid_cloud.user import RpcUser
|
|
from sentry.services.hybrid_cloud.util import region_silo_function
|
|
from sentry.services.hybrid_cloud.util import region_silo_function
|
|
from sentry.utils.committers import get_serialized_event_file_committers
|
|
from sentry.utils.committers import get_serialized_event_file_committers
|
|
from sentry.utils.performance_issues.base import get_url_from_span
|
|
from sentry.utils.performance_issues.base import get_url_from_span
|
|
-from sentry.utils.performance_issues.performance_detection import PerformanceProblem
|
|
|
|
|
|
+from sentry.utils.performance_issues.performance_problem import PerformanceProblem
|
|
from sentry.web.helpers import render_to_string
|
|
from sentry.web.helpers import render_to_string
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
if TYPE_CHECKING:
|
|
@@ -191,7 +191,7 @@ def get_group_settings_link(
|
|
notification_uuid: str | None = None,
|
|
notification_uuid: str | None = None,
|
|
**kwargs: Any,
|
|
**kwargs: Any,
|
|
) -> str:
|
|
) -> str:
|
|
- alert_rule_id: int | None = rule_details[0].id if rule_details and rule_details[0].id else None
|
|
|
|
|
|
+ alert_rule_id = rule_details[0].id if rule_details and rule_details[0].id else None
|
|
extra_params = ""
|
|
extra_params = ""
|
|
if alert_rule_id:
|
|
if alert_rule_id:
|
|
extra_params = get_email_link_extra_params(
|
|
extra_params = get_email_link_extra_params(
|
|
@@ -284,7 +284,7 @@ def has_integrations(organization: Organization, project: Project) -> bool:
|
|
return bool(project_plugins or organization_integrations)
|
|
return bool(project_plugins or organization_integrations)
|
|
|
|
|
|
|
|
|
|
-def is_alert_rule_integration(provider: IntegrationProvider) -> bool:
|
|
|
|
|
|
+def is_alert_rule_integration(provider: type[IntegrationProvider]) -> bool:
|
|
return any(
|
|
return any(
|
|
feature == (IntegrationFeatures.ALERT_RULE or IntegrationFeatures.ENTERPRISE_ALERT_RULE)
|
|
feature == (IntegrationFeatures.ALERT_RULE or IntegrationFeatures.ENTERPRISE_ALERT_RULE)
|
|
for feature in provider.features
|
|
for feature in provider.features
|
|
@@ -296,9 +296,7 @@ def has_alert_integration(project: Project) -> bool:
|
|
|
|
|
|
# check integrations
|
|
# check integrations
|
|
provider_keys = [
|
|
provider_keys = [
|
|
- cast(str, provider.key)
|
|
|
|
- for provider in integrations.all()
|
|
|
|
- if is_alert_rule_integration(provider)
|
|
|
|
|
|
+ provider.key for provider in integrations.all() if is_alert_rule_integration(provider)
|
|
]
|
|
]
|
|
if integration_service.get_integrations(organization_id=org.id, providers=provider_keys):
|
|
if integration_service.get_integrations(organization_id=org.id, providers=provider_keys):
|
|
return True
|
|
return True
|
|
@@ -364,7 +362,7 @@ def get_parent_and_repeating_spans(
|
|
return (parent_span, repeating_spans)
|
|
return (parent_span, repeating_spans)
|
|
|
|
|
|
|
|
|
|
-def occurrence_perf_to_email_html(context: Any) -> Any:
|
|
|
|
|
|
+def occurrence_perf_to_email_html(context: Any) -> str:
|
|
"""Generate the email HTML for an occurrence-backed performance issue alert"""
|
|
"""Generate the email HTML for an occurrence-backed performance issue alert"""
|
|
return render_to_string("sentry/emails/transactions.html", context)
|
|
return render_to_string("sentry/emails/transactions.html", context)
|
|
|
|
|
|
@@ -385,50 +383,42 @@ def get_spans(
|
|
return spans
|
|
return spans
|
|
|
|
|
|
|
|
|
|
-def get_transaction_data(event: Event) -> Any:
|
|
|
|
|
|
+def get_transaction_data(event: GroupEvent) -> str:
|
|
"""Get data about a transaction to populate alert emails."""
|
|
"""Get data about a transaction to populate alert emails."""
|
|
- evidence_data = event.occurrence.evidence_data
|
|
|
|
- if not evidence_data:
|
|
|
|
|
|
+ if event.occurrence is None or not event.occurrence.evidence_data:
|
|
return ""
|
|
return ""
|
|
-
|
|
|
|
- context = evidence_data
|
|
|
|
- return occurrence_perf_to_email_html(context)
|
|
|
|
|
|
+ return occurrence_perf_to_email_html(event.occurrence.evidence_data)
|
|
|
|
|
|
|
|
|
|
def get_generic_data(event: GroupEvent) -> Any:
|
|
def get_generic_data(event: GroupEvent) -> Any:
|
|
"""Get data about a generic issue type to populate alert emails."""
|
|
"""Get data about a generic issue type to populate alert emails."""
|
|
- generic_evidence = event.occurrence.evidence_display
|
|
|
|
-
|
|
|
|
- if not generic_evidence:
|
|
|
|
|
|
+ if event.occurrence is None or not event.occurrence.evidence_display:
|
|
return ""
|
|
return ""
|
|
|
|
|
|
- context = {}
|
|
|
|
- for row in generic_evidence:
|
|
|
|
- context[row.name] = row.value
|
|
|
|
-
|
|
|
|
|
|
+ context = {row.name: row.value for row in event.occurrence.evidence_display}
|
|
return generic_email_html(context)
|
|
return generic_email_html(context)
|
|
|
|
|
|
|
|
|
|
-def generic_email_html(context: Any) -> Any:
|
|
|
|
|
|
+def generic_email_html(context: Any) -> str:
|
|
"""Format issue evidence into a (stringified) HTML table for emails"""
|
|
"""Format issue evidence into a (stringified) HTML table for emails"""
|
|
return render_to_string("sentry/emails/generic_table.html", {"data": context})
|
|
return render_to_string("sentry/emails/generic_table.html", {"data": context})
|
|
|
|
|
|
|
|
|
|
-def get_performance_issue_alert_subtitle(event: Event) -> str:
|
|
|
|
|
|
+def get_performance_issue_alert_subtitle(event: GroupEvent) -> str:
|
|
"""Generate the issue alert subtitle for performance issues"""
|
|
"""Generate the issue alert subtitle for performance issues"""
|
|
- return cast(
|
|
|
|
- str, event.occurrence.evidence_data.get("repeating_spans_compact", "").replace("`", '"')
|
|
|
|
- )
|
|
|
|
|
|
+ if event.occurrence is None:
|
|
|
|
+ return ""
|
|
|
|
+ return event.occurrence.evidence_data.get("repeating_spans_compact", "").replace("`", '"')
|
|
|
|
|
|
|
|
|
|
def get_notification_group_title(
|
|
def get_notification_group_title(
|
|
group: Group, event: Event | GroupEvent, max_length: int = 255, **kwargs: str
|
|
group: Group, event: Event | GroupEvent, max_length: int = 255, **kwargs: str
|
|
) -> str:
|
|
) -> str:
|
|
if isinstance(event, GroupEvent) and event.occurrence is not None:
|
|
if isinstance(event, GroupEvent) and event.occurrence is not None:
|
|
- issue_title: str = event.occurrence.issue_title
|
|
|
|
|
|
+ issue_title = event.occurrence.issue_title
|
|
return issue_title
|
|
return issue_title
|
|
else:
|
|
else:
|
|
- event_title: str = event.title
|
|
|
|
|
|
+ event_title = event.title
|
|
return event_title
|
|
return event_title
|
|
|
|
|
|
|
|
|
|
@@ -637,7 +627,7 @@ class ConsecutiveDBQueriesProblemContext(PerformanceProblemContext):
|
|
this is where thresholds come in
|
|
this is where thresholds come in
|
|
"""
|
|
"""
|
|
independent_spans = [self._find_span_by_id(id) for id in self.problem.offender_span_ids]
|
|
independent_spans = [self._find_span_by_id(id) for id in self.problem.offender_span_ids]
|
|
- consecutive_spans = [self._find_span_by_id(id) for id in self.problem.cause_span_ids]
|
|
|
|
|
|
+ consecutive_spans = [self._find_span_by_id(id) for id in self.problem.cause_span_ids or ()]
|
|
total_duration = self._sum_span_duration(consecutive_spans)
|
|
total_duration = self._sum_span_duration(consecutive_spans)
|
|
|
|
|
|
max_independent_span_duration = max(
|
|
max_independent_span_duration = max(
|