diff --git a/dev-packages/browser-integration-tests/suites/replay/captureReplay/test.ts b/dev-packages/browser-integration-tests/suites/replay/captureReplay/test.ts index ff200ae09869..92634cf92b5a 100644 --- a/dev-packages/browser-integration-tests/suites/replay/captureReplay/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/captureReplay/test.ts @@ -29,6 +29,7 @@ sentryTest('should capture replays (@sentry/browser export)', async ({ getLocalT replay_id: expect.stringMatching(/\w{32}/), replay_start_timestamp: expect.any(Number), segment_id: 0, + segment_names: [], replay_type: 'session', event_id: expect.stringMatching(/\w{32}/), environment: 'production', @@ -77,6 +78,7 @@ sentryTest('should capture replays (@sentry/browser export)', async ({ getLocalT replay_id: expect.stringMatching(/\w{32}/), replay_start_timestamp: expect.any(Number), segment_id: 1, + segment_names: [], replay_type: 'session', event_id: expect.stringMatching(/\w{32}/), environment: 'production', diff --git a/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts b/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts index 3a312bdb0e2a..05b419bf9636 100644 --- a/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts @@ -29,6 +29,7 @@ sentryTest('should capture replays (@sentry/replay export)', async ({ getLocalTe replay_id: expect.stringMatching(/\w{32}/), replay_start_timestamp: expect.any(Number), segment_id: 0, + segment_names: [], replay_type: 'session', event_id: expect.stringMatching(/\w{32}/), environment: 'production', @@ -77,6 +78,7 @@ sentryTest('should capture replays (@sentry/replay export)', async ({ getLocalTe replay_id: expect.stringMatching(/\w{32}/), replay_start_timestamp: expect.any(Number), segment_id: 1, + segment_names: [], replay_type: 'session', event_id: expect.stringMatching(/\w{32}/), environment: 'production', diff --git a/dev-packages/browser-integration-tests/utils/replayEventTemplates.ts b/dev-packages/browser-integration-tests/utils/replayEventTemplates.ts index b84818738d74..6f6ba2136ea8 100644 --- a/dev-packages/browser-integration-tests/utils/replayEventTemplates.ts +++ b/dev-packages/browser-integration-tests/utils/replayEventTemplates.ts @@ -12,6 +12,7 @@ const DEFAULT_REPLAY_EVENT = { replay_id: expect.stringMatching(/\w{32}/), replay_start_timestamp: expect.any(Number), segment_id: 0, + segment_names: [], replay_type: 'session', event_id: expect.stringMatching(/\w{32}/), environment: 'production', diff --git a/packages/core/src/types/replay.ts b/packages/core/src/types/replay.ts index a23f548aa357..862be2ff07ef 100644 --- a/packages/core/src/types/replay.ts +++ b/packages/core/src/types/replay.ts @@ -9,6 +9,7 @@ export interface ReplayEvent extends Event { replay_start_timestamp?: number; error_ids: string[]; trace_ids: string[]; + segment_names: string[]; replay_id: string; segment_id: number; replay_type: ReplayRecordingMode; diff --git a/packages/replay-internal/src/coreHandlers/handleAfterSegmentSpanEnd.ts b/packages/replay-internal/src/coreHandlers/handleAfterSegmentSpanEnd.ts deleted file mode 100644 index 6d98b94559ec..000000000000 --- a/packages/replay-internal/src/coreHandlers/handleAfterSegmentSpanEnd.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Span } from '@sentry/core'; -import { spanIsSampled } from '@sentry/core'; -import type { ReplayContainer } from '../types'; -import { addTraceIdToContext } from './util/addTraceIdToContext'; - -type AfterSegmentSpanEndCallback = (segmentSpan: Span) => void; - -export function handleAfterSegmentSpanEnd(replay: ReplayContainer): AfterSegmentSpanEndCallback { - return (segmentSpan: Span) => { - if (!replay.isEnabled() || !spanIsSampled(segmentSpan)) { - return; - } - - const traceId = segmentSpan.spanContext().traceId; - if (traceId) { - addTraceIdToContext(replay, traceId); - } - }; -} diff --git a/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts b/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts index 3e78959580f0..aeb4a1ef75b1 100644 --- a/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts +++ b/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts @@ -2,7 +2,7 @@ import type { ErrorEvent, Event, TransactionEvent, TransportMakeRequestResponse import { setTimeout } from '@sentry/browser-utils'; import type { ReplayContainer } from '../types'; import { isErrorEvent, isTransactionEvent } from '../util/eventUtils'; -import { addTraceIdToContext } from './util/addTraceIdToContext'; +import { addSegmentDetailsToContext } from './util/addSegmentDetailsToContext'; type AfterSendEventCallback = (event: Event, sendResponse: TransportMakeRequestResponse) => void; @@ -33,10 +33,7 @@ export function handleAfterSendEvent(replay: ReplayContainer): AfterSendEventCal } function handleTransactionEvent(replay: ReplayContainer, event: TransactionEvent): void { - const traceId = event.contexts?.trace?.trace_id; - if (traceId) { - addTraceIdToContext(replay, traceId); - } + addSegmentDetailsToContext(replay, event.contexts?.trace?.trace_id, event.transaction); } function handleErrorEvent(replay: ReplayContainer, event: ErrorEvent): void { diff --git a/packages/replay-internal/src/coreHandlers/handleProcessSegmentSpan.ts b/packages/replay-internal/src/coreHandlers/handleProcessSegmentSpan.ts new file mode 100644 index 000000000000..cdc8184a7dd0 --- /dev/null +++ b/packages/replay-internal/src/coreHandlers/handleProcessSegmentSpan.ts @@ -0,0 +1,15 @@ +import type { StreamedSpanJSON } from '@sentry/core'; +import type { ReplayContainer } from '../types'; +import { addSegmentDetailsToContext } from './util/addSegmentDetailsToContext'; + +type ProcessSegmentSpanCallback = (spanJSON: StreamedSpanJSON) => void; + +export function handleProcessSegmentSpan(replay: ReplayContainer): ProcessSegmentSpanCallback { + return (spanJSON: StreamedSpanJSON) => { + if (!replay.isEnabled()) { + return; + } + + addSegmentDetailsToContext(replay, spanJSON.trace_id, spanJSON.name || undefined); + }; +} diff --git a/packages/replay-internal/src/coreHandlers/util/addSegmentDetailsToContext.ts b/packages/replay-internal/src/coreHandlers/util/addSegmentDetailsToContext.ts new file mode 100644 index 000000000000..88c873983fd8 --- /dev/null +++ b/packages/replay-internal/src/coreHandlers/util/addSegmentDetailsToContext.ts @@ -0,0 +1,13 @@ +import type { ReplayContainer } from '../../types'; + +const MAX_CONTEXT_VALUES = 100; + +export function addSegmentDetailsToContext(replay: ReplayContainer, traceId?: string, segmentName?: string): void { + const replayContext = replay.getContext(); + if (traceId && replayContext.traceIds.size < MAX_CONTEXT_VALUES) { + replayContext.traceIds.add(traceId); + } + if (segmentName && replayContext.segmentNames.size < MAX_CONTEXT_VALUES) { + replayContext.segmentNames.add(segmentName); + } +} diff --git a/packages/replay-internal/src/coreHandlers/util/addTraceIdToContext.ts b/packages/replay-internal/src/coreHandlers/util/addTraceIdToContext.ts deleted file mode 100644 index a3302c1ba661..000000000000 --- a/packages/replay-internal/src/coreHandlers/util/addTraceIdToContext.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { ReplayContainer } from '../../types'; - -const MAX_TRACE_IDS = 100; - -export function addTraceIdToContext(replay: ReplayContainer, traceId: string): void { - const replayContext = replay.getContext(); - if (replayContext.traceIds.size < MAX_TRACE_IDS) { - replayContext.traceIds.add(traceId); - } -} diff --git a/packages/replay-internal/src/replay.ts b/packages/replay-internal/src/replay.ts index 947d0485ed3d..439ae124f4a5 100644 --- a/packages/replay-internal/src/replay.ts +++ b/packages/replay-internal/src/replay.ts @@ -195,6 +195,7 @@ export class ReplayContainer implements ReplayContainerInterface { this._context = { errorIds: new Set(), traceIds: new Set(), + segmentNames: new Set(), urls: [], initialTimestamp: Date.now(), initialUrl: '', @@ -1122,6 +1123,7 @@ export class ReplayContainer implements ReplayContainerInterface { // XXX: `initialTimestamp` and `initialUrl` do not get cleared this._context.errorIds.clear(); this._context.traceIds.clear(); + this._context.segmentNames.clear(); this._context.urls = []; } @@ -1154,6 +1156,7 @@ export class ReplayContainer implements ReplayContainerInterface { initialUrl: this._context.initialUrl, errorIds: Array.from(this._context.errorIds), traceIds: Array.from(this._context.traceIds), + segmentNames: Array.from(this._context.segmentNames), urls: this._context.urls, }; diff --git a/packages/replay-internal/src/types/replay.ts b/packages/replay-internal/src/types/replay.ts index 95cfbdd849bf..955393c2f225 100644 --- a/packages/replay-internal/src/types/replay.ts +++ b/packages/replay-internal/src/types/replay.ts @@ -360,6 +360,11 @@ export interface PopEventContext extends CommonEventContext { * List of Sentry trace ids that have occurred during a replay segment */ traceIds: Array; + + /** + * List of Sentry segment names that have occurred during a replay segment + */ + segmentNames: Array; } /** @@ -375,6 +380,11 @@ export interface InternalEventContext extends CommonEventContext { * Set of Sentry trace ids that have occurred during a replay segment */ traceIds: Set; + + /** + * Set of Sentry segment names that have occurred during a replay segment + */ + segmentNames: Set; } export type Sampled = false | 'session' | 'buffer'; diff --git a/packages/replay-internal/src/util/addGlobalListeners.ts b/packages/replay-internal/src/util/addGlobalListeners.ts index 7ca4fd91f4f1..ac4d228f8976 100644 --- a/packages/replay-internal/src/util/addGlobalListeners.ts +++ b/packages/replay-internal/src/util/addGlobalListeners.ts @@ -1,7 +1,7 @@ import type { DynamicSamplingContext } from '@sentry/core'; import { addEventProcessor, getClient } from '@sentry/core'; import { addClickKeypressInstrumentationHandler, addHistoryInstrumentationHandler } from '@sentry/browser-utils'; -import { handleAfterSegmentSpanEnd } from '../coreHandlers/handleAfterSegmentSpanEnd'; +import { handleProcessSegmentSpan } from '../coreHandlers/handleProcessSegmentSpan'; import { handleAfterSendEvent } from '../coreHandlers/handleAfterSendEvent'; import { handleBeforeSendEvent } from '../coreHandlers/handleBeforeSendEvent'; import { handleBreadcrumbs } from '../coreHandlers/handleBreadcrumbs'; @@ -44,7 +44,7 @@ export function addGlobalListeners(replay: ReplayContainer): void { } }); - client.on('afterSegmentSpanEnd', handleAfterSegmentSpanEnd(replay)); + client.on('processSegmentSpan', handleProcessSegmentSpan(replay)); client.on('spanStart', span => { replay.lastActiveSpan = span; diff --git a/packages/replay-internal/src/util/sendReplayRequest.ts b/packages/replay-internal/src/util/sendReplayRequest.ts index 777b3f970712..6dea2a9821eb 100644 --- a/packages/replay-internal/src/util/sendReplayRequest.ts +++ b/packages/replay-internal/src/util/sendReplayRequest.ts @@ -26,7 +26,7 @@ export async function sendReplayRequest({ }, }); - const { urls, errorIds, traceIds, initialTimestamp } = eventContext; + const { urls, errorIds, traceIds, segmentNames, initialTimestamp } = eventContext; const client = getClient(); const scope = getCurrentScope(); @@ -43,6 +43,7 @@ export async function sendReplayRequest({ timestamp: timestamp / 1000, error_ids: errorIds, trace_ids: traceIds, + segment_names: segmentNames, urls, replay_id: replayId, segment_id, diff --git a/packages/replay-internal/test/integration/coreHandlers/handleAfterSegmentSpanEnd.test.ts b/packages/replay-internal/test/integration/coreHandlers/handleAfterSegmentSpanEnd.test.ts deleted file mode 100644 index 45c754ce153a..000000000000 --- a/packages/replay-internal/test/integration/coreHandlers/handleAfterSegmentSpanEnd.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -/** - * @vitest-environment jsdom - */ - -import type { Span } from '@sentry/core'; -import { getClient } from '@sentry/core'; -import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; -import type { ReplayContainer } from '../../../src/replay'; -import { resetSdkMock } from '../../mocks/resetSdkMock'; - -let replay: ReplayContainer; - -describe('Integration | coreHandlers | handleAfterSegmentSpanEnd', () => { - beforeAll(() => { - vi.useFakeTimers(); - }); - - afterEach(() => { - replay.stop(); - }); - - it('records traceIds from afterSegmentSpanEnd', async () => { - ({ replay } = await resetSdkMock({ - replayOptions: { - stickySession: false, - }, - sentryOptions: { - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 0.0, - }, - })); - - const client = getClient()!; - - client.emit('afterSegmentSpanEnd', { - spanContext: () => ({ traceId: 'trace-stream-1', spanId: 'span1', traceFlags: 1 }), - } as unknown as Span); - - client.emit('afterSegmentSpanEnd', { - spanContext: () => ({ traceId: 'trace-stream-2', spanId: 'span2', traceFlags: 1 }), - } as unknown as Span); - - expect(Array.from(replay.getContext().traceIds)).toEqual(['trace-stream-1', 'trace-stream-2']); - }); - - it('limits traceIds from afterSegmentSpanEnd to max. 100', async () => { - ({ replay } = await resetSdkMock({ - replayOptions: { - stickySession: false, - }, - sentryOptions: { - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 0.0, - }, - })); - - const client = getClient()!; - - for (let i = 0; i < 150; i++) { - client.emit('afterSegmentSpanEnd', { - spanContext: () => ({ traceId: `tr-${i}`, spanId: `sp-${i}`, traceFlags: 1 }), - } as unknown as Span); - } - - expect(replay.getContext().traceIds.size).toBe(100); - expect(Array.from(replay.getContext().traceIds)).toEqual( - Array(100) - .fill(undefined) - .map((_, i) => `tr-${i}`), - ); - }); - - it('does not record traceIds from afterSegmentSpanEnd when replay is disabled', async () => { - ({ replay } = await resetSdkMock({ - replayOptions: { - stickySession: false, - }, - sentryOptions: { - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 0.0, - }, - })); - - const client = getClient()!; - - replay['_isEnabled'] = false; - - client.emit('afterSegmentSpanEnd', { - spanContext: () => ({ traceId: 'trace-stream-1', spanId: 'span1', traceFlags: 1 }), - } as unknown as Span); - - expect(Array.from(replay.getContext().traceIds)).toEqual([]); - }); - - it('does not record traceIds for unsampled spans', async () => { - ({ replay } = await resetSdkMock({ - replayOptions: { - stickySession: false, - }, - sentryOptions: { - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 0.0, - }, - })); - - const client = getClient()!; - - client.emit('afterSegmentSpanEnd', { - spanContext: () => ({ traceId: 'trace-unsampled', spanId: 'span1', traceFlags: 0 }), - } as unknown as Span); - - expect(Array.from(replay.getContext().traceIds)).toEqual([]); - }); -}); diff --git a/packages/replay-internal/test/integration/coreHandlers/handleAfterSendEvent.test.ts b/packages/replay-internal/test/integration/coreHandlers/handleAfterSendEvent.test.ts index f45441a34caf..5fa9c0abec1f 100644 --- a/packages/replay-internal/test/integration/coreHandlers/handleAfterSendEvent.test.ts +++ b/packages/replay-internal/test/integration/coreHandlers/handleAfterSendEvent.test.ts @@ -54,9 +54,10 @@ describe('Integration | coreHandlers | handleAfterSendEvent', () => { expect(Array.from(replay.getContext().errorIds)).toEqual(['err2']); expect(Array.from(replay.getContext().traceIds)).toEqual([]); + expect(Array.from(replay.getContext().segmentNames)).toEqual([]); }); - it('records traceIds from sent transaction events', async () => { + it('records traceIds and segmentNames from sent transaction events', async () => { ({ replay } = await resetSdkMock({ replayOptions: { stickySession: false, @@ -85,17 +86,59 @@ describe('Integration | coreHandlers | handleAfterSendEvent', () => { expect(Array.from(replay.getContext().errorIds)).toEqual([]); expect(Array.from(replay.getContext().traceIds)).toEqual(['tr2']); + expect(Array.from(replay.getContext().segmentNames)).toEqual(['/organizations/:orgId/replays/:replaySlug/']); // Does not affect error session await vi.advanceTimersToNextTimerAsync(); expect(Array.from(replay.getContext().errorIds)).toEqual([]); expect(Array.from(replay.getContext().traceIds)).toEqual(['tr2']); + expect(Array.from(replay.getContext().segmentNames)).toEqual(['/organizations/:orgId/replays/:replaySlug/']); expect(replay.isEnabled()).toBe(true); expect(replay.isPaused()).toBe(false); expect(replay.recordingMode).toBe('buffer'); }); + it('records traceId but not segmentName for nameless transaction events', async () => { + ({ replay } = await resetSdkMock({ + replayOptions: { + stickySession: false, + }, + sentryOptions: { + replaysSessionSampleRate: 0.0, + replaysOnErrorSampleRate: 1.0, + }, + })); + + const handler = handleAfterSendEvent(replay); + + const namelessTransaction = Transaction('tr-nameless', { transaction: undefined }); + handler(namelessTransaction, { statusCode: 200 }); + + expect(Array.from(replay.getContext().traceIds)).toEqual(['tr-nameless']); + expect(Array.from(replay.getContext().segmentNames)).toEqual([]); + }); + + it('records segmentName but not traceId for transaction events with missing trace context', async () => { + ({ replay } = await resetSdkMock({ + replayOptions: { + stickySession: false, + }, + sentryOptions: { + replaysSessionSampleRate: 0.0, + replaysOnErrorSampleRate: 1.0, + }, + })); + + const handler = handleAfterSendEvent(replay); + + const noTraceTransaction = Transaction(undefined, { contexts: {} }); + handler(noTraceTransaction, { statusCode: 200 }); + + expect(Array.from(replay.getContext().traceIds)).toEqual([]); + expect(Array.from(replay.getContext().segmentNames)).toEqual(['/organizations/:orgId/replays/:replaySlug/']); + }); + it('limits errorIds to max. 100', async () => { ({ replay } = await resetSdkMock({ replayOptions: { @@ -146,6 +189,8 @@ describe('Integration | coreHandlers | handleAfterSendEvent', () => { .fill(undefined) .map((_, i) => `tr-${i}`), ); + expect(replay.getContext().segmentNames.size).toBe(1); + expect(Array.from(replay.getContext().segmentNames)).toEqual(['/organizations/:orgId/replays/:replaySlug/']); }); it('flushes when in buffer mode', async () => { diff --git a/packages/replay-internal/test/integration/coreHandlers/handleProcessSegmentSpan.test.ts b/packages/replay-internal/test/integration/coreHandlers/handleProcessSegmentSpan.test.ts new file mode 100644 index 000000000000..cc670fbf5d45 --- /dev/null +++ b/packages/replay-internal/test/integration/coreHandlers/handleProcessSegmentSpan.test.ts @@ -0,0 +1,172 @@ +/** + * @vitest-environment jsdom + */ + +import type { StreamedSpanJSON } from '@sentry/core'; +import { getClient } from '@sentry/core'; +import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; +import type { ReplayContainer } from '../../../src/replay'; +import { resetSdkMock } from '../../mocks/resetSdkMock'; + +let replay: ReplayContainer; + +describe('Integration | coreHandlers | handleProcessSegmentSpan', () => { + beforeAll(() => { + vi.useFakeTimers(); + }); + + afterEach(() => { + replay.stop(); + }); + + it('records traceIds and segment names from processSegmentSpan', async () => { + ({ replay } = await resetSdkMock({ + replayOptions: { + stickySession: false, + }, + sentryOptions: { + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + }, + })); + + const client = getClient()!; + + client.emit('processSegmentSpan', { + trace_id: 'trace-stream-1', + span_id: 'span1', + name: 'GET /api/users', + is_segment: true, + start_timestamp: 0, + end_timestamp: 1, + status: 'ok', + } as StreamedSpanJSON); + + client.emit('processSegmentSpan', { + trace_id: 'trace-stream-2', + span_id: 'span2', + name: 'POST /api/items', + is_segment: true, + start_timestamp: 0, + end_timestamp: 1, + status: 'ok', + } as StreamedSpanJSON); + + expect(Array.from(replay.getContext().traceIds)).toEqual(['trace-stream-1', 'trace-stream-2']); + expect(Array.from(replay.getContext().segmentNames)).toEqual(['GET /api/users', 'POST /api/items']); + }); + + it('limits traceIds from processSegmentSpan to max. 100', async () => { + ({ replay } = await resetSdkMock({ + replayOptions: { + stickySession: false, + }, + sentryOptions: { + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + }, + })); + + const client = getClient()!; + + for (let i = 0; i < 150; i++) { + client.emit('processSegmentSpan', { + trace_id: `tr-${i}`, + span_id: `sp-${i}`, + name: `segment-${i}`, + is_segment: true, + start_timestamp: 0, + end_timestamp: 1, + status: 'ok', + } as StreamedSpanJSON); + } + + expect(replay.getContext().traceIds.size).toBe(100); + expect(Array.from(replay.getContext().traceIds)).toEqual( + Array(100) + .fill(undefined) + .map((_, i) => `tr-${i}`), + ); + }); + + it('does not record traceIds from processSegmentSpan when replay is disabled', async () => { + ({ replay } = await resetSdkMock({ + replayOptions: { + stickySession: false, + }, + sentryOptions: { + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + }, + })); + + const client = getClient()!; + + replay['_isEnabled'] = false; + + client.emit('processSegmentSpan', { + trace_id: 'trace-stream-1', + span_id: 'span1', + name: 'GET /api/users', + is_segment: true, + start_timestamp: 0, + end_timestamp: 1, + status: 'ok', + } as StreamedSpanJSON); + + expect(Array.from(replay.getContext().traceIds)).toEqual([]); + }); + + it('records traceId but not segmentName for segment spans with empty names', async () => { + ({ replay } = await resetSdkMock({ + replayOptions: { + stickySession: false, + }, + sentryOptions: { + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + }, + })); + + const client = getClient()!; + + client.emit('processSegmentSpan', { + trace_id: 'trace-stream-1', + span_id: 'span1', + name: '', + is_segment: true, + start_timestamp: 0, + end_timestamp: 1, + status: 'ok', + } as StreamedSpanJSON); + + expect(Array.from(replay.getContext().traceIds)).toEqual(['trace-stream-1']); + expect(Array.from(replay.getContext().segmentNames)).toEqual([]); + }); + + it('records segmentName but not traceId for segment spans with missing trace_id', async () => { + ({ replay } = await resetSdkMock({ + replayOptions: { + stickySession: false, + }, + sentryOptions: { + replaysSessionSampleRate: 1.0, + replaysOnErrorSampleRate: 0.0, + }, + })); + + const client = getClient()!; + + client.emit('processSegmentSpan', { + span_id: 'span1', + name: 'GET /api/users', + is_segment: true, + start_timestamp: 0, + end_timestamp: 1, + status: 'ok', + } as StreamedSpanJSON); + + expect(Array.from(replay.getContext().traceIds)).toEqual([]); + expect(Array.from(replay.getContext().segmentNames)).toEqual(['GET /api/users']); + }); +}); diff --git a/packages/replay-internal/test/integration/sampling.test.ts b/packages/replay-internal/test/integration/sampling.test.ts index 9ffa00c349c6..a86bf54b924a 100644 --- a/packages/replay-internal/test/integration/sampling.test.ts +++ b/packages/replay-internal/test/integration/sampling.test.ts @@ -38,6 +38,7 @@ describe('Integration | sampling', () => { expect(replay.getContext()).toEqual({ errorIds: new Set(), traceIds: new Set(), + segmentNames: new Set(), urls: [], initialTimestamp: expect.any(Number), initialUrl: '', @@ -79,6 +80,7 @@ describe('Integration | sampling', () => { initialTimestamp: expect.any(Number), initialUrl: 'http://localhost:3000/', traceIds: new Set(), + segmentNames: new Set(), urls: ['http://localhost:3000/'], }); expect(replay.recordingMode).toBe('buffer'); diff --git a/packages/replay-internal/test/integration/session.test.ts b/packages/replay-internal/test/integration/session.test.ts index 1c4b49bb1fad..31322dc4a3f8 100644 --- a/packages/replay-internal/test/integration/session.test.ts +++ b/packages/replay-internal/test/integration/session.test.ts @@ -253,6 +253,7 @@ describe('Integration | session', () => { urls: [], errorIds: new Set(), traceIds: new Set(), + segmentNames: new Set(), }); });