123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- import {EventType} from '@sentry-internal/rrweb';
- import {serializedNodeWithId} from '@sentry-internal/rrweb-snapshot';
- import type {ReplaySpan as TReplaySpan} from 'sentry/views/replays/types';
- type FullSnapshotEvent = {
- data: {
- initialOffset: {
- left: number;
- top: number;
- };
- node: serializedNodeWithId;
- };
- timestamp: number;
- type: EventType.FullSnapshot;
- };
- type BaseReplayProps = {
- timestamp: Date;
- };
- export function ReplaySegmentInit({
- height = 600,
- href = 'http://localhost/',
- timestamp = new Date(),
- width = 800,
- }: BaseReplayProps & {
- height: number;
- href: string;
- width: number;
- }) {
- return [
- {
- type: EventType.DomContentLoaded,
- timestamp: timestamp.getTime(), // rrweb timestamps are in ms
- },
- {
- type: EventType.Load,
- timestamp: timestamp.getTime(), // rrweb timestamps are in ms
- },
- {
- type: EventType.Meta,
- data: {href, width, height},
- timestamp: timestamp.getTime(), // rrweb timestamps are in ms
- },
- ];
- }
- export function ReplaySegmentFullsnapshot({
- timestamp,
- childNodes,
- }: BaseReplayProps & {childNodes: serializedNodeWithId[]}): [FullSnapshotEvent] {
- return [
- {
- type: EventType.FullSnapshot,
- timestamp: timestamp.getTime(),
- data: {
- initialOffset: {
- top: 0,
- left: 0,
- },
- node: {
- type: 0, // NodeType.DocumentType
- id: 0,
- childNodes: [
- ReplayRRWebNode({
- tagName: 'body',
- attributes: {
- style:
- 'margin:0; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu;',
- },
- childNodes,
- }),
- ],
- },
- },
- },
- ];
- }
- export function ReplaySegmentConsole({timestamp = new Date()}: BaseReplayProps) {
- return ReplaySegmentBreadcrumb({
- timestamp,
- payload: {
- timestamp: timestamp.getTime() / 1000, // sentry data inside rrweb is in seconds
- type: 'default',
- category: 'console',
- data: {
- arguments: [
- './src/pages/template/Header.js\n Line 14: The href attribute requires a valid value to be accessible. Provide a valid, navigable address as the href value.',
- ],
- logger: 'console',
- },
- level: 'warning',
- message:
- './src/pages/template/Header.js\n Line 14: The href attribute requires a valid value to be accessible. Provide a valid, navigable address as the href value.',
- },
- });
- }
- export function ReplaySegmentNavigation({
- timestamp = new Date(),
- hrefFrom = '/',
- hrefTo = '/profile/',
- }: BaseReplayProps & {hrefFrom: string; hrefTo: string}) {
- return ReplaySegmentBreadcrumb({
- timestamp,
- payload: {
- timestamp: timestamp.getTime() / 1000, // sentry data inside rrweb is in seconds
- type: 'default',
- category: 'navigation',
- data: {
- from: hrefFrom,
- to: hrefTo,
- },
- },
- });
- }
- export function ReplaySegmentBreadcrumb({
- timestamp = new Date(),
- payload,
- }: BaseReplayProps & {payload: any}) {
- return [
- {
- type: EventType.Custom,
- timestamp: timestamp.getTime(), // rrweb timestamps are in ms
- data: {
- tag: 'breadcrumb',
- payload,
- },
- },
- ];
- }
- export function ReplaySegmentSpan({
- timestamp = new Date(),
- payload,
- }: BaseReplayProps & {payload: any}) {
- return [
- {
- type: EventType.Custom,
- timestamp: timestamp.getTime(), // rrweb timestamps are in ms
- data: {
- tag: 'performanceSpan',
- payload,
- },
- },
- ];
- }
- const nextRRWebId = (function () {
- let __rrwebID = 0;
- return () => ++__rrwebID;
- })();
- export function ReplayRRWebNode({
- id,
- tagName,
- attributes,
- childNodes,
- textContent,
- }: {
- attributes?: Record<string, string>;
- childNodes?: serializedNodeWithId[];
- id?: number;
- tagName?: string;
- textContent?: string;
- }): serializedNodeWithId {
- id = id ?? nextRRWebId();
- if (tagName) {
- return {
- type: 2, // NodeType.Element
- id,
- tagName,
- attributes: attributes ?? {},
- childNodes: childNodes ?? [],
- };
- }
- return {
- type: 3, // NodeType.Text
- id,
- textContent: textContent ?? '',
- };
- }
- export function ReplayRRWebDivHelloWorld() {
- return ReplayRRWebNode({
- tagName: 'div',
- childNodes: [
- ReplayRRWebNode({
- tagName: 'h1',
- attributes: {style: 'text-align: center;'},
- childNodes: [
- ReplayRRWebNode({
- textContent: 'Hello World',
- }),
- ],
- }),
- ],
- });
- }
- export function ReplaySpanPayload({
- startTimestamp = new Date(),
- endTimestamp = new Date(),
- ...extra
- }: {
- op: string;
- data?: Record<string, any>;
- description?: string;
- endTimestamp?: Date;
- startTimestamp?: Date;
- }): TReplaySpan<Record<string, any>> {
- return {
- data: {},
- id: '0',
- ...extra,
- startTimestamp: startTimestamp.getTime() / 1000, // in seconds, with ms precision
- endTimestamp: endTimestamp?.getTime() / 1000, // in seconds, with ms precision
- timestamp: startTimestamp?.getTime(), // in ms, same as startTimestamp
- };
- }
- export function ReplaySpanPayloadNavigate({
- description = 'http://test.com',
- endTimestamp = new Date(),
- startTimestamp = new Date(),
- }: {
- // The url goes into the description field
- description: string;
- endTimestamp: Date;
- startTimestamp: Date;
- }) {
- const duration = endTimestamp.getTime() - startTimestamp.getTime(); // in MS
- return ReplaySpanPayload({
- op: 'navigation.navigate',
- description,
- startTimestamp,
- endTimestamp,
- data: {
- size: 1149,
- decodedBodySize: 1712,
- encodedBodySize: 849,
- duration,
- domInteractive: duration - 200,
- domContentLoadedEventStart: duration - 50,
- domContentLoadedEventEnd: duration - 48,
- loadEventStart: duration, // real value would be approx the same
- loadEventEnd: duration, // real value would be approx the same
- domComplete: duration, // real value would be approx the same
- redirectCount: 0,
- },
- });
- }
|