diff --git a/packages/replay/src/replay.ts b/packages/replay/src/replay.ts index 5642b66b8b5a..718b658ad82d 100644 --- a/packages/replay/src/replay.ts +++ b/packages/replay/src/replay.ts @@ -1,7 +1,7 @@ /* eslint-disable max-lines */ // TODO: We might want to split this file up import { EventType, record } from '@sentry-internal/rrweb'; import { captureException, getCurrentHub } from '@sentry/core'; -import type { Breadcrumb, ReplayRecordingMode } from '@sentry/types'; +import type { Breadcrumb, ReplayRecordingMode, Transaction } from '@sentry/types'; import { logger } from '@sentry/utils'; import { @@ -68,6 +68,12 @@ export class ReplayContainer implements ReplayContainerInterface { */ public recordingMode: ReplayRecordingMode = 'session'; + /** + * The current or last active transcation. + * This is only available when performance is enabled. + */ + public lastTransaction?: Transaction; + /** * These are here so we can overwrite them in tests etc. * @hidden @@ -614,6 +620,19 @@ export class ReplayContainer implements ReplayContainerInterface { return res; } + /** + * This will get the parametrized route name of the current page. + * This is only available if performance is enabled, and if an instrumented router is used. + */ + public getCurrentRoute(): string | undefined { + const lastTransaction = this.lastTransaction || getCurrentHub().getScope().getTransaction(); + if (!lastTransaction || !['route', 'custom'].includes(lastTransaction.metadata.source)) { + return undefined; + } + + return lastTransaction.name; + } + /** * Initialize and start all listeners to varying events (DOM, * Performance Observer, Recording, Sentry SDK, etc) diff --git a/packages/replay/src/types.ts b/packages/replay/src/types.ts index 393eed5802a8..42758c1b06d9 100644 --- a/packages/replay/src/types.ts +++ b/packages/replay/src/types.ts @@ -4,6 +4,7 @@ import type { ReplayRecordingData, ReplayRecordingMode, SentryWrappedXMLHttpRequest, + Transaction, XhrBreadcrumbHint, } from '@sentry/types'; @@ -535,6 +536,7 @@ export interface ReplayContainer { session: Session | undefined; recordingMode: ReplayRecordingMode; timeouts: Timeouts; + lastTransaction?: Transaction; throttledAddEvent: ( event: RecordingEvent, isCheckout?: boolean, @@ -559,6 +561,7 @@ export interface ReplayContainer { getSessionId(): string | undefined; checkAndHandleExpiredSession(): boolean | void; setInitialState(): void; + getCurrentRoute(): string | undefined; } export interface ReplayPerformanceEntry { diff --git a/packages/replay/src/util/addGlobalListeners.ts b/packages/replay/src/util/addGlobalListeners.ts index e5096f397fae..c1adbc72e787 100644 --- a/packages/replay/src/util/addGlobalListeners.ts +++ b/packages/replay/src/util/addGlobalListeners.ts @@ -40,6 +40,16 @@ export function addGlobalListeners(replay: ReplayContainer): void { dsc.replay_id = replayId; } }); + + client.on('startTransaction', transaction => { + replay.lastTransaction = transaction; + }); + + // We may be missing the initial startTransaction due to timing issues, + // so we capture it on finish again. + client.on('finishTransaction', transaction => { + replay.lastTransaction = transaction; + }); } }