11import functools
22from collections .abc import Generator , Iterator
3- from typing import Any
3+ from typing import Any , TypedDict
44
55import requests
66import sentry_sdk
2727from sentry .utils import json
2828
2929
30+ class ErrorEvent (TypedDict ):
31+ id : str
32+ title : str
33+ message : str
34+ timestamp : float
35+ category : str
36+
37+
3038@region_silo_endpoint
3139@extend_schema (tags = ["Replays" ])
3240class ProjectReplaySummarizeBreadcrumbsEndpoint (ProjectEndpoint ):
@@ -82,20 +90,20 @@ def get(self, request: Request, project: Project, replay_id: str) -> Response:
8290 )
8391
8492
85- def fetch_error_details (project_id : int , error_ids : list [str ]) -> list [dict [ str , Any ] ]:
86- """Fetch error details given error IDs."""
93+ def fetch_error_details (project_id : int , error_ids : list [str ]) -> list [ErrorEvent ]:
94+ """Fetch error details given error IDs and return a list of ErrorEvent objects ."""
8795 try :
8896 node_ids = [Event .generate_node_id (project_id , event_id = id ) for id in error_ids ]
8997 events = nodestore .backend .get_multi (node_ids )
9098
9199 return [
92- {
93- " category" : "error" ,
94- "id" : event_id ,
95- " title" : data .get ("title" , "" ),
96- " timestamp" : data .get ("timestamp" , 0.0 ),
97- " message" : data .get ("message" , "" ),
98- }
100+ ErrorEvent (
101+ category = "error" ,
102+ id = event_id ,
103+ title = data .get ("title" , "" ),
104+ timestamp = data .get ("timestamp" , 0.0 ),
105+ message = data .get ("message" , "" ),
106+ )
99107 for event_id , data in zip (error_ids , events .values ())
100108 if data is not None
101109 ]
@@ -104,24 +112,24 @@ def fetch_error_details(project_id: int, error_ids: list[str]) -> list[dict[str,
104112 return []
105113
106114
107- def generate_error_log_message (error : dict [ str , Any ] ) -> str :
108- title = error . get ( "title" , "" )
109- message = error . get ( "message" , "" )
110- timestamp = error . get ( "timestamp" , 0 )
115+ def generate_error_log_message (error : ErrorEvent ) -> str :
116+ title = error [ "title" ]
117+ message = error [ "message" ]
118+ timestamp = error [ "timestamp" ]
111119
112120 return f"User experienced an error: '{ title } : { message } ' at { timestamp } "
113121
114122
115123def get_request_data (
116- iterator : Iterator [tuple [int , memoryview ]], error_events : list [dict [ str , Any ] ]
124+ iterator : Iterator [tuple [int , memoryview ]], error_events : list [ErrorEvent ]
117125) -> list [str ]:
118126 # Sort error events by timestamp
119- error_events .sort (key = lambda x : x . get ( "timestamp" , 0 ) )
127+ error_events .sort (key = lambda x : x [ "timestamp" ] )
120128 return list (gen_request_data (iterator , error_events ))
121129
122130
123131def gen_request_data (
124- iterator : Iterator [tuple [int , memoryview ]], error_events : list [dict [ str , Any ] ]
132+ iterator : Iterator [tuple [int , memoryview ]], error_events : list [ErrorEvent ]
125133) -> Generator [str ]:
126134 """Generate log messages from events and errors in chronological order."""
127135 error_idx = 0
@@ -131,9 +139,10 @@ def gen_request_data(
131139 events = json .loads (segment .tobytes ().decode ("utf-8" ))
132140 for event in events :
133141 # Check if we need to yield any error messages that occurred before this event
134- while error_idx < len (error_events ) and error_events [error_idx ][
135- "timestamp"
136- ] < event .get ("timestamp" , 0 ):
142+ while (
143+ error_idx < len (error_events )
144+ and error_events [error_idx ]["timestamp" ] < event ["timestamp" ]
145+ ):
137146 error = error_events [error_idx ]
138147 yield generate_error_log_message (error )
139148 error_idx += 1
@@ -151,7 +160,7 @@ def gen_request_data(
151160
152161@sentry_sdk .trace
153162def analyze_recording_segments (
154- error_events : list [dict [ str , Any ] ],
163+ error_events : list [ErrorEvent ],
155164 segments : list [RecordingSegmentStorageMeta ],
156165) -> dict [str , Any ]:
157166 # Combine breadcrumbs and error details
0 commit comments