|
7 | 7 | import sentry_sdk |
8 | 8 |
|
9 | 9 | from sentry import nodestore |
| 10 | +from sentry.api.utils import default_start_end_dates |
10 | 11 | from sentry.constants import ObjectStatus |
11 | 12 | from sentry.issues.grouptype import FeedbackGroup |
12 | 13 | from sentry.models.project import Project |
13 | | -from sentry.replays.query import query_trace_connected_events |
| 14 | +from sentry.replays.post_process import process_raw_response |
| 15 | +from sentry.replays.query import query_replay_instance, query_trace_connected_events |
14 | 16 | from sentry.replays.usecases.ingest.event_parser import EventType |
15 | 17 | from sentry.replays.usecases.ingest.event_parser import ( |
16 | 18 | get_timestamp_ms as get_replay_event_timestamp_ms, |
17 | 19 | ) |
18 | 20 | from sentry.replays.usecases.ingest.event_parser import parse_network_content_lengths, which |
| 21 | +from sentry.replays.usecases.reader import fetch_segments_metadata, iter_segment_data |
19 | 22 | from sentry.search.events.types import SnubaParams |
20 | 23 | from sentry.services.eventstore.models import Event |
21 | 24 | from sentry.snuba.referrer import Referrer |
22 | | -from sentry.utils import json |
| 25 | +from sentry.utils import json, metrics |
23 | 26 |
|
24 | 27 | logger = logging.getLogger(__name__) |
25 | 28 |
|
@@ -449,3 +452,78 @@ def _parse_url(s: str, trunc_length: int) -> str: |
449 | 452 | if len(s) > trunc_length: |
450 | 453 | return s[:trunc_length] + " [truncated]" |
451 | 454 | return s |
| 455 | + |
| 456 | + |
| 457 | +def rpc_get_replay_summary_logs( |
| 458 | + project_id: int, replay_id: str, num_segments: int |
| 459 | +) -> dict[str, Any]: |
| 460 | + """ |
| 461 | + RPC call for Seer. Downloads a replay's segment data, queries associated errors, and parses this into summary logs. |
| 462 | + """ |
| 463 | + |
| 464 | + project = Project.objects.get(id=project_id) |
| 465 | + # Last 90 days. We don't support date filters in /summarize/. |
| 466 | + start, end = default_start_end_dates() |
| 467 | + |
| 468 | + # Fetch the replay's error and trace IDs from the replay_id. |
| 469 | + snuba_response = query_replay_instance( |
| 470 | + project_id=project.id, |
| 471 | + replay_id=replay_id, |
| 472 | + start=start, |
| 473 | + end=end, |
| 474 | + organization=project.organization, |
| 475 | + request_user_id=None, # This is for the viewed_by_me field which is unused for summaries. |
| 476 | + ) |
| 477 | + processed_response = process_raw_response( |
| 478 | + snuba_response, |
| 479 | + fields=[], # Defaults to all fields. |
| 480 | + ) |
| 481 | + |
| 482 | + # 404s should be handled in the originating Sentry endpoint. |
| 483 | + # If the replay is missing here just return an empty response. |
| 484 | + if not processed_response: |
| 485 | + return {"logs": []} |
| 486 | + |
| 487 | + error_ids = processed_response[0].get("error_ids", []) |
| 488 | + trace_ids = processed_response[0].get("trace_ids", []) |
| 489 | + |
| 490 | + # Fetch same-trace errors. |
| 491 | + trace_connected_errors = fetch_trace_connected_errors( |
| 492 | + project=project, |
| 493 | + trace_ids=trace_ids, |
| 494 | + start=start, |
| 495 | + end=end, |
| 496 | + limit=100, |
| 497 | + ) |
| 498 | + trace_connected_error_ids = {x["id"] for x in trace_connected_errors} |
| 499 | + |
| 500 | + # Fetch directly linked errors, if they weren't returned by the trace query. |
| 501 | + direct_errors = fetch_error_details( |
| 502 | + project_id=project.id, |
| 503 | + error_ids=[x for x in error_ids if x not in trace_connected_error_ids], |
| 504 | + ) |
| 505 | + |
| 506 | + error_events = direct_errors + trace_connected_errors |
| 507 | + |
| 508 | + # Metric names kept for backwards compatibility. |
| 509 | + metrics.distribution( |
| 510 | + "replays.endpoints.project_replay_summary.direct_errors", |
| 511 | + value=len(direct_errors), |
| 512 | + ) |
| 513 | + metrics.distribution( |
| 514 | + "replays.endpoints.project_replay_summary.trace_connected_errors", |
| 515 | + value=len(trace_connected_errors), |
| 516 | + ) |
| 517 | + metrics.distribution( |
| 518 | + "replays.endpoints.project_replay_summary.num_trace_ids", |
| 519 | + value=len(trace_ids), |
| 520 | + ) |
| 521 | + |
| 522 | + # Download segment data. |
| 523 | + segment_md = fetch_segments_metadata(project.id, replay_id, 0, num_segments) |
| 524 | + segment_data = iter_segment_data(segment_md) |
| 525 | + |
| 526 | + # Combine replay and error data and parse into logs. |
| 527 | + logs = get_summary_logs(segment_data, error_events, project.id) |
| 528 | + |
| 529 | + return {"logs": logs} |
0 commit comments