Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
c264e69
chore(issues): Indicate duration when "Since First Seen" is selected …
amy-chen23 May 26, 2026
0f46976
fix(issues): Move user serialization out of loop in ignored issues ha…
shashjar May 26, 2026
9845280
ref(preprod): Simplify project filtering in latest base snapshot endp…
NicoHinderling May 26, 2026
7424a02
fix(traces): Handle deleted groups in trace endpoint (#116248)
wedamija May 26, 2026
2d0cdcf
fix(feedback): Downgrade log level for insufficient feedback count (#…
wedamija May 26, 2026
d13651a
test(spans): Remove tests for deprecated standalone spans storage (#1…
phacops May 26, 2026
d8ddccf
fix(issues): Fix undefined variable in `StreamGroupSerializerSnuba` f…
shashjar May 26, 2026
616d958
fix(ratelimits): Handle AnonymousUser missing is_sentry_app attribute…
wedamija May 26, 2026
9d1f340
fix(replays): Remove timeline icon z-index workaround (#116255)
scttcper May 26, 2026
ca85432
chore(issues): Remove redundant check on `event_id` (#116261)
shashjar May 26, 2026
de57e53
chore(issues): Use standard logging pattern in group details endpoint…
shashjar May 26, 2026
6caf163
chore(alerts): Clean up usage of AlertRuleSerializerResponse (#116218)
ceorourke May 26, 2026
cd2fcde
test(snuba): Update tests for removal of boolean double-writing (#111…
volokluev May 26, 2026
d74a8bc
fix(preprod): Reduce snapshot download concurrency to prevent stream …
NicoHinderling May 27, 2026
fdac7a3
feat(webhooks): Add dry run check to sentry app webhook path (#116265)
Christinarlong May 27, 2026
7417a7c
fix(issues): Align collapsed activity row (#116266)
scttcper May 27, 2026
bbad42a
feat(autofix): Allow non seat based seer to skip setup (#116208)
Zylphrex May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/sentry/api/endpoints/organization_events_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,12 @@ def load_span_serialized_performance_issues(self, light: bool) -> None:
offender_span_ids = problem.evidence_data.get("offender_span_ids", [])
for group_id in self.event["occurrence_to_issue_id"][problem.id]:
if group_id not in memoized_groups:
memoized_groups[group_id] = Group.objects.get(
id=group_id, project=self.event["project.id"]
)
try:
memoized_groups[group_id] = Group.objects.get(
id=group_id, project=self.event["project.id"]
)
except Group.DoesNotExist:
continue
group = memoized_groups[group_id]
if event_span.get("span_id") in offender_span_ids:
start_timestamp = float(event_span["precise.start_ts"])
Expand Down
6 changes: 4 additions & 2 deletions src/sentry/api/serializers/models/group_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,8 +490,10 @@ def get_attrs(
)
attrs[item]["sentryAppIssues"] = sentry_app_issues

if self._expand("latestEventHasAttachments") and features.has(
"organizations:event-attachments", item.project.organization
if (
self._expand("latestEventHasAttachments")
and item_list
and features.has("organizations:event-attachments", item_list[0].project.organization)
):
for item in item_list:
latest_event = item.get_latest_event()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def get(self, request: Request, organization: Organization) -> Response:
)

if len(recent_feedbacks) < MIN_FEEDBACKS_CONTEXT:
logger.error("Too few feedbacks to generate categories")
logger.info("Too few feedbacks to generate categories")
return Response(
{
"categories": None,
Expand Down
10 changes: 0 additions & 10 deletions src/sentry/incidents/action_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
from sentry.charts.types import ChartSize
from sentry.constants import CRASH_RATE_ALERT_AGGREGATE_ALIAS
from sentry.incidents.charts import build_metric_alert_chart
from sentry.incidents.endpoints.serializers.alert_rule import AlertRuleSerializerResponse
from sentry.incidents.endpoints.serializers.incident import DetailedIncidentSerializerResponse
from sentry.incidents.endpoints.serializers.utils import get_fake_id_from_object_id
from sentry.incidents.models.alert_rule import (
AlertRuleDetectionType,
Expand Down Expand Up @@ -152,8 +150,6 @@ def format_duration(minutes: int | float) -> str:
def generate_incident_trigger_email_context(
project: Project,
organization: Organization,
alert_rule_serialized_response: AlertRuleSerializerResponse,
incident_serialized_response: DetailedIncidentSerializerResponse,
metric_issue_context: MetricIssueContext,
alert_context: AlertContext,
open_period_context: OpenPeriodContext,
Expand Down Expand Up @@ -207,8 +203,6 @@ def generate_incident_trigger_email_context(
try:
chart_url = build_metric_alert_chart(
organization=organization,
alert_rule_serialized_response=alert_rule_serialized_response,
selected_incident_serialized=incident_serialized_response,
snuba_query=snuba_query,
alert_context=alert_context,
open_period_context=open_period_context,
Expand Down Expand Up @@ -302,8 +296,6 @@ def email_users(
metric_issue_context: MetricIssueContext,
open_period_context: OpenPeriodContext,
alert_context: AlertContext,
alert_rule_serialized_response: AlertRuleSerializerResponse,
incident_serialized_response: DetailedIncidentSerializerResponse,
trigger_status: TriggerStatus,
targets: list[tuple[int, str]],
project: Project,
Expand All @@ -323,8 +315,6 @@ def email_users(
project=project,
organization=project.organization,
metric_issue_context=metric_issue_context,
alert_rule_serialized_response=alert_rule_serialized_response,
incident_serialized_response=incident_serialized_response,
alert_context=alert_context,
open_period_context=open_period_context,
trigger_status=trigger_status,
Expand Down
112 changes: 27 additions & 85 deletions src/sentry/incidents/charts.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
from sentry.api.utils import get_datetime_from_stats_period
from sentry.charts import backend as charts
from sentry.charts.types import ChartSize, ChartType
from sentry.incidents.endpoints.serializers.alert_rule import AlertRuleSerializerResponse
from sentry.incidents.endpoints.serializers.incident import DetailedIncidentSerializerResponse
from sentry.incidents.logic import translate_aggregate_field
from sentry.incidents.typings.metric_detector import AlertContext, OpenPeriodContext
from sentry.models.apikey import ApiKey
Expand All @@ -27,7 +25,6 @@
from sentry.workflow_engine.endpoints.serializers.detector_serializer import (
DetectorSerializerResponse,
)
from sentry.workflow_engine.models import AlertRuleDetector

CRASH_FREE_SESSIONS = "percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate"
CRASH_FREE_USERS = "percentage(users_crashed, users) AS _crash_rate_alert_aggregate"
Expand Down Expand Up @@ -140,41 +137,17 @@ def fetch_metric_issue_open_periods(
) -> list[Any]:
detector_id = open_period_identifier
try:
# temporarily fetch the alert rule ID from the detector ID
alert_rule_detector = AlertRuleDetector.objects.filter(
detector_id=open_period_identifier, alert_rule_id__isnull=False
).first()
if alert_rule_detector is not None:
# open_period_identifier is a metric detector ID -> get the alert rule ID
open_period_identifier = alert_rule_detector.alert_rule_id
resp = client.get(
auth=ApiKey(organization_id=organization.id, scope_list=["org:read"]),
user=user,
path=f"/organizations/{organization.slug}/open-periods/",
params={
"detectorId": detector_id,
"bucketSize": time_window,
**time_period,
},
)

if features.has(
"organizations:workflow-engine-ui",
organization,
):
resp = client.get(
auth=ApiKey(organization_id=organization.id, scope_list=["org:read"]),
user=user,
path=f"/organizations/{organization.slug}/open-periods/",
params={
"detectorId": detector_id,
"bucketSize": time_window,
**time_period,
},
)
else:
resp = client.get(
auth=ApiKey(organization_id=organization.id, scope_list=["org:read"]),
user=user,
path=f"/organizations/{organization.slug}/incidents/",
params={
"alertRule": open_period_identifier,
"expand": "activities",
"includeSnapshots": True,
"project": -1,
**time_period,
},
)
return resp.data
except Exception as exc:
logger.error(
Expand All @@ -187,11 +160,9 @@ def fetch_metric_issue_open_periods(

def build_metric_alert_chart(
organization: Organization,
alert_rule_serialized_response: AlertRuleSerializerResponse,
snuba_query: SnubaQuery,
alert_context: AlertContext,
open_period_context: OpenPeriodContext | None = None,
selected_incident_serialized: DetailedIncidentSerializerResponse | None = None,
period: str | None = None,
start: str | None = None,
end: str | None = None,
Expand All @@ -206,22 +177,12 @@ def build_metric_alert_chart(
dataset = Dataset(snuba_query.dataset)
query_type = SnubaQuery.Type(snuba_query.type)
is_crash_free_alert = query_type == SnubaQuery.Type.CRASH_RATE
using_new_charts = features.has(
"organizations:workflow-engine-ui",
organization,

style = (
ChartType.SLACK_METRIC_DETECTOR_SESSIONS
if is_crash_free_alert
else ChartType.SLACK_METRIC_DETECTOR_EVENTS
)
if is_crash_free_alert:
style = (
ChartType.SLACK_METRIC_DETECTOR_SESSIONS
if using_new_charts
else ChartType.SLACK_METRIC_ALERT_SESSIONS
)
else:
style = (
ChartType.SLACK_METRIC_DETECTOR_EVENTS
if using_new_charts
else ChartType.SLACK_METRIC_ALERT_EVENTS
)

if open_period_context:
time_period = incident_date_range(
Expand All @@ -237,33 +198,17 @@ def build_metric_alert_chart(
"start": period_start.strftime(TIME_FORMAT),
"end": timezone.now().strftime(TIME_FORMAT),
}
if features.has(
"organizations:workflow-engine-ui",
organization,
):
# TODO(mifu67): create detailed serializer for open period, pass here.
# But we don't need it to render the chart, so it's fine for now.
chart_data_detector = {
"detector": detector_serialized_response,
"openPeriods": fetch_metric_issue_open_periods(
organization,
alert_context.action_identifier_id,
time_period,
user,
snuba_query.time_window,
),
}
else:
chart_data_alert_rule = {
"rule": alert_rule_serialized_response,
"selectedIncident": selected_incident_serialized,
"incidents": fetch_metric_issue_open_periods(
organization,
alert_context.action_identifier_id,
time_period,
user,
),
}

chart_data_detector = {
"detector": detector_serialized_response,
"openPeriods": fetch_metric_issue_open_periods(
organization,
alert_context.action_identifier_id,
time_period,
user,
snuba_query.time_window,
),
}

allow_mri = features.has(
"organizations:insights-alerts",
Expand Down Expand Up @@ -343,10 +288,7 @@ def build_metric_alert_chart(
)

try:
if using_new_charts:
chart_data.update(chart_data_detector)
else:
chart_data.update(chart_data_alert_rule)
chart_data.update(chart_data_detector)
return charts.generate_chart(style, chart_data, size=size)
except RuntimeError as exc:
logger.error(
Expand Down
12 changes: 1 addition & 11 deletions src/sentry/integrations/discord/actions/metric_alert.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

from sentry import features
from sentry.incidents.charts import build_metric_alert_chart
from sentry.incidents.endpoints.serializers.alert_rule import AlertRuleSerializerResponse
from sentry.incidents.endpoints.serializers.incident import DetailedIncidentSerializerResponse
from sentry.incidents.typings.metric_detector import (
AlertContext,
MetricIssueContext,
Expand Down Expand Up @@ -37,25 +35,17 @@ def send_incident_alert_notification(
notification_context: NotificationContext,
metric_issue_context: MetricIssueContext,
open_period_context: OpenPeriodContext,
alert_rule_serialized_response: AlertRuleSerializerResponse | None,
incident_serialized_response: DetailedIncidentSerializerResponse | None,
detector_serialized_response: DetectorSerializerResponse | None = None,
notification_uuid: str | None = None,
) -> bool:
chart_url = None
if (
features.has("organizations:metric-alert-chartcuterie", organization)
and alert_rule_serialized_response
and incident_serialized_response
):
if features.has("organizations:metric-alert-chartcuterie", organization):
try:
chart_url = build_metric_alert_chart(
organization=organization,
alert_rule_serialized_response=alert_rule_serialized_response,
snuba_query=metric_issue_context.snuba_query,
alert_context=alert_context,
open_period_context=open_period_context,
selected_incident_serialized=incident_serialized_response,
subscription=metric_issue_context.subscription,
detector_serialized_response=detector_serialized_response,
)
Expand Down
4 changes: 0 additions & 4 deletions src/sentry/integrations/msteams/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import enum
import logging

from sentry.incidents.endpoints.serializers.alert_rule import AlertRuleSerializerResponse
from sentry.incidents.endpoints.serializers.incident import DetailedIncidentSerializerResponse
from sentry.incidents.typings.metric_detector import (
AlertContext,
MetricIssueContext,
Expand Down Expand Up @@ -115,8 +113,6 @@ def send_incident_alert_notification(
notification_context: NotificationContext,
metric_issue_context: MetricIssueContext,
open_period_context: OpenPeriodContext,
alert_rule_serialized_response: AlertRuleSerializerResponse | None,
incident_serialized_response: DetailedIncidentSerializerResponse | None,
notification_uuid: str | None = None,
) -> bool:
from .card_builder.incident_attachment import build_incident_attachment
Expand Down
16 changes: 1 addition & 15 deletions src/sentry/integrations/slack/utils/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
from sentry import features
from sentry.constants import METRIC_ALERTS_THREAD_DEFAULT, ObjectStatus
from sentry.incidents.charts import build_metric_alert_chart
from sentry.incidents.endpoints.serializers.alert_rule import AlertRuleSerializerResponse
from sentry.incidents.endpoints.serializers.incident import DetailedIncidentSerializerResponse
from sentry.incidents.models.incident import IncidentStatus
from sentry.incidents.typings.metric_detector import (
AlertContext,
Expand Down Expand Up @@ -129,25 +127,17 @@ def _build_notification_payload(
alert_context: AlertContext,
metric_issue_context: MetricIssueContext,
open_period_context: OpenPeriodContext,
alert_rule_serialized_response: AlertRuleSerializerResponse | None,
incident_serialized_response: DetailedIncidentSerializerResponse | None,
detector_serialized_response: DetectorSerializerResponse | None,
notification_uuid: str | None,
) -> tuple[str, str]:
chart_url = None
if (
features.has("organizations:metric-alert-chartcuterie", organization)
and alert_rule_serialized_response
and incident_serialized_response
):
if features.has("organizations:metric-alert-chartcuterie", organization):
try:
chart_url = build_metric_alert_chart(
organization=organization,
alert_rule_serialized_response=alert_rule_serialized_response,
snuba_query=metric_issue_context.snuba_query,
alert_context=alert_context,
open_period_context=open_period_context,
selected_incident_serialized=incident_serialized_response,
subscription=metric_issue_context.subscription,
detector_serialized_response=detector_serialized_response,
)
Expand Down Expand Up @@ -290,8 +280,6 @@ def send_incident_alert_notification(
notification_context: NotificationContext,
metric_issue_context: MetricIssueContext,
open_period_context: OpenPeriodContext,
alert_rule_serialized_response: AlertRuleSerializerResponse | None,
incident_serialized_response: DetailedIncidentSerializerResponse | None,
detector_serialized_response: DetectorSerializerResponse | None = None,
notification_uuid: str | None = None,
) -> bool:
Expand All @@ -315,8 +303,6 @@ def send_incident_alert_notification(
alert_context=alert_context,
metric_issue_context=metric_issue_context,
open_period_context=open_period_context,
alert_rule_serialized_response=alert_rule_serialized_response,
incident_serialized_response=incident_serialized_response,
notification_uuid=notification_uuid,
detector_serialized_response=detector_serialized_response,
)
Expand Down
4 changes: 2 additions & 2 deletions src/sentry/issues/endpoints/group_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
from sentry.users.services.user.service import user_service
from sentry.utils import metrics

delete_logger = logging.getLogger("sentry.deletions.api")
logger = logging.getLogger(__name__)


def get_group_global_count(group: Group) -> str:
Expand Down Expand Up @@ -390,7 +390,7 @@ def put(self, request: Request, group: Group) -> Response:
sample_rate=1.0,
tags={"status": e.status_code, "detail": "group_details:update:Response"},
)
logging.exception(
logger.exception(
"group_details:put client.ApiError",
)
return Response(e.body, status=e.status_code)
Expand Down
3 changes: 1 addition & 2 deletions src/sentry/issues/endpoints/organization_group_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,7 @@ def get(self, request: Request, organization: Organization) -> Response:
serialized_groups = serialize(
groups, request.user, serializer(), request=request
)
if event_id:
serialized_groups[0]["matchingEventId"] = event_id
serialized_groups[0]["matchingEventId"] = event_id
response = Response(serialized_groups)
response["X-Sentry-Direct-Hit"] = "1"
return response
Expand Down
Loading
Loading