8
8
9
9
from sentry import nodestore
10
10
from sentry .constants import ObjectStatus
11
- from sentry .issues .grouptype import FeedbackGroup
12
11
from sentry .models .project import Project
13
- from sentry .replays .query import query_trace_connected_events
14
12
from sentry .replays .usecases .ingest .event_parser import EventType
15
13
from sentry .replays .usecases .ingest .event_parser import (
16
14
get_timestamp_ms as get_replay_event_timestamp_ms ,
17
15
)
18
16
from sentry .replays .usecases .ingest .event_parser import parse_network_content_lengths , which
19
- from sentry .search .events .types import SnubaParams
17
+ from sentry .search .events .builder .discover import DiscoverQueryBuilder
18
+ from sentry .search .events .types import QueryBuilderConfig , SnubaParams
20
19
from sentry .services .eventstore .models import Event
20
+ from sentry .snuba .dataset import Dataset
21
21
from sentry .snuba .referrer import Referrer
22
22
from sentry .utils import json
23
+ from sentry .utils .snuba import bulk_snuba_queries
23
24
24
25
logger = logging .getLogger (__name__ )
25
26
@@ -98,86 +99,54 @@ def fetch_trace_connected_errors(
98
99
organization = project .organization ,
99
100
)
100
101
101
- # Query errors dataset
102
- error_query = query_trace_connected_events (
103
- dataset_label = "errors" ,
102
+ # Generate a query for each trace ID. This will be executed in bulk.
103
+ error_query = DiscoverQueryBuilder (
104
+ Dataset .Events ,
105
+ params = {},
106
+ snuba_params = snuba_params ,
107
+ query = f"trace:{ trace_id } " ,
104
108
selected_columns = [
105
109
"id" ,
106
110
"timestamp_ms" ,
107
111
"timestamp" ,
108
112
"title" ,
109
113
"message" ,
110
114
],
111
- query = f"trace:{ trace_id } " ,
112
- snuba_params = snuba_params ,
113
115
orderby = ["id" ],
114
116
limit = 100 ,
115
- referrer = Referrer .API_REPLAY_SUMMARIZE_BREADCRUMBS .value ,
117
+ config = QueryBuilderConfig (
118
+ auto_fields = False ,
119
+ ),
116
120
)
117
121
queries .append (error_query )
118
122
119
- # Query issuePlatform dataset - this returns all other IP events,
120
- # such as feedback and performance issues.
121
- issue_query = query_trace_connected_events (
122
- dataset_label = "issuePlatform" ,
123
- selected_columns = [
124
- "event_id" ,
125
- "title" ,
126
- "subtitle" ,
127
- "timestamp" ,
128
- "occurrence_type_id" ,
129
- ],
130
- query = f"trace:{ trace_id } " ,
131
- snuba_params = snuba_params ,
132
- orderby = ["event_id" ],
133
- limit = 100 ,
134
- referrer = Referrer .API_REPLAY_SUMMARIZE_BREADCRUMBS .value ,
135
- )
136
- queries .append (issue_query )
137
-
138
123
if not queries :
139
124
return []
140
125
126
+ # Execute all queries
127
+ results = bulk_snuba_queries (
128
+ [query .get_snql_query () for query in queries ],
129
+ referrer = Referrer .API_REPLAY_SUMMARIZE_BREADCRUMBS .value ,
130
+ )
131
+
141
132
# Process results and convert to EventDict objects
142
133
error_events = []
143
- seen_event_ids = set () # Track seen event IDs to avoid duplicates
144
-
145
- for query in queries :
146
- result = query
147
- error_data = result ["data" ]
134
+ for result , query in zip (results , queries ):
135
+ error_data = query .process_results (result )["data" ]
148
136
149
137
for event in error_data :
150
- event_id = event .get ("id" ) or event .get ("event_id" )
151
-
152
- # Skip if we've already seen this event
153
- if event_id in seen_event_ids :
154
- continue
155
-
156
- seen_event_ids .add (event_id )
157
-
158
138
timestamp = _parse_iso_timestamp_to_ms (
159
139
event .get ("timestamp_ms" )
160
140
) or _parse_iso_timestamp_to_ms (event .get ("timestamp" ))
161
- message = event .get ("subtitle" , "" ) or event .get ("message" , "" )
162
-
163
- if event .get ("occurrence_type_id" ) == FeedbackGroup .type_id :
164
- category = "feedback"
165
- else :
166
- category = "error"
167
141
168
- # NOTE: The issuePlatform dataset query can return feedback.
169
- # We also fetch feedback from nodestore in fetch_feedback_details
170
- # for feedback breadcrumbs.
171
- # We avoid creating duplicate feedback logs
172
- # by filtering for unique feedback IDs during log generation.
173
142
if timestamp :
174
143
error_events .append (
175
144
EventDict (
176
- category = category ,
177
- id = event_id ,
145
+ category = "error" ,
146
+ id = event [ "id" ] ,
178
147
title = event .get ("title" , "" ),
179
148
timestamp = timestamp ,
180
- message = message ,
149
+ message = event . get ( " message" , "" ) ,
181
150
)
182
151
)
183
152
@@ -238,7 +207,7 @@ def get_summary_logs(
238
207
error_events : list [EventDict ],
239
208
project_id : int ,
240
209
) -> list [str ]:
241
- # Sort error events by timestamp. This list includes all feedback events still.
210
+ # Sort error events by timestamp
242
211
error_events .sort (key = lambda x : x ["timestamp" ])
243
212
return list (generate_summary_logs (segment_data , error_events , project_id ))
244
213
@@ -248,12 +217,8 @@ def generate_summary_logs(
248
217
error_events : list [EventDict ],
249
218
project_id ,
250
219
) -> Generator [str ]:
251
- """
252
- Generate log messages from events and errors in chronological order.
253
- Avoid processing duplicate feedback events.
254
- """
220
+ """Generate log messages from events and errors in chronological order."""
255
221
error_idx = 0
256
- seen_feedback_ids = set ()
257
222
258
223
# Process segments
259
224
for _ , segment in segment_data :
@@ -267,39 +232,23 @@ def generate_summary_logs(
267
232
error_idx < len (error_events ) and error_events [error_idx ]["timestamp" ] < timestamp
268
233
):
269
234
error = error_events [error_idx ]
270
-
271
- if error ["category" ] == "error" :
272
- yield generate_error_log_message (error )
273
- elif error ["category" ] == "feedback" :
274
- seen_feedback_ids .add (error ["id" ])
275
- yield generate_feedback_log_message (error )
276
-
235
+ yield generate_error_log_message (error )
277
236
error_idx += 1
278
237
279
238
# Yield the current event's log message
280
239
if event_type == EventType .FEEDBACK :
281
240
feedback_id = event ["data" ]["payload" ].get ("data" , {}).get ("feedbackId" )
282
- # Filter out duplicate feedback events.
283
- if feedback_id not in seen_feedback_ids :
284
- seen_feedback_ids .add (feedback_id )
285
- feedback = fetch_feedback_details (feedback_id , project_id )
286
-
287
- if feedback :
288
- yield generate_feedback_log_message (feedback )
241
+ feedback = fetch_feedback_details (feedback_id , project_id )
242
+ if feedback :
243
+ yield generate_feedback_log_message (feedback )
289
244
290
245
elif message := as_log_message (event ):
291
246
yield message
292
247
293
248
# Yield any remaining error messages
294
249
while error_idx < len (error_events ):
295
250
error = error_events [error_idx ]
296
-
297
- if error ["category" ] == "error" :
298
- yield generate_error_log_message (error )
299
- elif error ["category" ] == "feedback" :
300
- seen_feedback_ids .add (error ["id" ])
301
- yield generate_feedback_log_message (error )
302
-
251
+ yield generate_error_log_message (error )
303
252
error_idx += 1
304
253
305
254
0 commit comments