123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- import type {BreadcrumbTypeNavigation, Crumb} from 'sentry/types/breadcrumbs';
- import {BreadcrumbType} from 'sentry/types/breadcrumbs';
- import type {Event, EventTransaction} from 'sentry/types/event';
- import {
- breadcrumbFactory,
- replayTimestamps,
- rrwebEventListFactory,
- spansFactory,
- } from 'sentry/utils/replays/replayDataUtils';
- import type {
- MemorySpanType,
- RecordingEvent,
- ReplayCrumb,
- ReplayError,
- ReplayRecord,
- ReplaySpan,
- } from 'sentry/views/replays/types';
- interface ReplayReaderParams {
- breadcrumbs: ReplayCrumb[] | undefined;
- errors: ReplayError[] | undefined;
- /**
- * The root Replay event, created at the start of the browser session.
- */
- event: Event | undefined;
- /**
- * The captured data from rrweb.
- * Saved as N attachments that belong to the root Replay event.
- */
- rrwebEvents: RecordingEvent[] | undefined;
- spans: ReplaySpan[] | undefined;
- }
- type RequiredNotNull<T> = {
- [P in keyof T]: NonNullable<T[P]>;
- };
- export default class ReplayReader {
- static factory({breadcrumbs, event, errors, rrwebEvents, spans}: ReplayReaderParams) {
- if (!breadcrumbs || !event || !rrwebEvents || !spans || !errors) {
- return null;
- }
- return new ReplayReader({breadcrumbs, event, errors, rrwebEvents, spans});
- }
- private constructor({
- breadcrumbs,
- event,
- errors,
- rrwebEvents,
- spans,
- }: RequiredNotNull<ReplayReaderParams>) {
- const {startTimestampMs, endTimestampMs} = replayTimestamps(
- rrwebEvents,
- breadcrumbs,
- spans
- );
- this.spans = spansFactory(spans);
- this.breadcrumbs = breadcrumbFactory(
- startTimestampMs,
- event,
- errors,
- breadcrumbs,
- this.spans
- );
- this.rrwebEvents = rrwebEventListFactory(
- startTimestampMs,
- endTimestampMs,
- rrwebEvents
- );
- this.event = {
- ...event,
- startTimestamp: startTimestampMs / 1000,
- endTimestamp: endTimestampMs / 1000,
- } as EventTransaction;
- const urls = (
- this.getRawCrumbs().filter(
- crumb => crumb.category === BreadcrumbType.NAVIGATION
- ) as BreadcrumbTypeNavigation[]
- )
- .map(crumb => crumb.data?.to)
- .filter(Boolean) as string[];
- this.replayRecord = {
- countErrors: this.getRawCrumbs().filter(
- crumb => crumb.category === BreadcrumbType.ERROR
- ).length,
- countSegments: 0,
- countUrls: urls.length,
- errorIds: [],
- dist: this.event.dist,
- duration: endTimestampMs - startTimestampMs,
- environment: null,
- finishedAt: new Date(endTimestampMs), // TODO(replay): Convert from string to Date when reading API
- longestTransaction: 0,
- platform: this.event.platform,
- projectId: this.event.projectID,
- projectSlug: '', // TODO(replay): Read from useProject to fill this in
- release: null, // event.release is not a string, expected to be `version@1.4`
- replayId: this.event.id,
- sdkName: this.event.sdk?.name,
- sdkVersion: this.event.sdk?.version,
- startedAt: new Date(startTimestampMs), // TODO(replay): Convert from string to Date when reading API
- tags: this.event.tags.reduce((tags, {key, value}) => {
- tags[key] = value;
- return tags;
- }, {} as ReplayRecord['tags']),
- title: this.event.title,
- traceIds: [],
- urls,
- userAgent: '',
- user: {
- email: this.event.user?.email,
- id: this.event.user?.id,
- ipAddress: this.event.user?.ip_address,
- name: this.event.user?.name,
- },
- } as ReplayRecord;
- }
- private event: EventTransaction;
- private replayRecord: ReplayRecord;
- private rrwebEvents: RecordingEvent[];
- private breadcrumbs: Crumb[];
- private spans: ReplaySpan[];
- getEvent = () => {
- return this.event;
- };
- /**
- * @returns Duration of Replay (milliseonds)
- */
- getDurationMs = () => {
- return this.replayRecord.duration;
- };
- getReplay = () => {
- return this.replayRecord;
- };
- getRRWebEvents = () => {
- return this.rrwebEvents;
- };
- getRawCrumbs = () => {
- return this.breadcrumbs;
- };
- getRawSpans = () => {
- return this.spans;
- };
- isMemorySpan = (span: ReplaySpan): span is MemorySpanType => {
- return span.op === 'memory';
- };
- isNetworkSpan = (span: ReplaySpan) => {
- return !this.isMemorySpan(span) && !span.op.includes('paint');
- };
- }
|