diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index 94521c672d3d..1696a3684b2e 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -51,6 +51,7 @@ export { } from '@sentry/browser-utils'; export type { CachedRouteProvider, RouteProvider } from '@sentry/browser-utils'; export { interactionsIntegration } from './integrations/interactions'; +export { linkedTracesIntegration } from './integrations/linkedTraces'; export { longTasksIntegration } from './integrations/longTasks'; export { xhrTracingIntegration } from './integrations/xhrTracing'; diff --git a/packages/browser/src/integrations/linkedTraces.ts b/packages/browser/src/integrations/linkedTraces.ts new file mode 100644 index 000000000000..db4148a627df --- /dev/null +++ b/packages/browser/src/integrations/linkedTraces.ts @@ -0,0 +1,36 @@ +import type { IntegrationFn } from '@sentry/core'; +import { defineIntegration } from '@sentry/core'; +import { linkTraces } from '../tracing/linkedTraces'; + +interface LinkedTracesOptions { + /** + * Where the previous trace is stored: `'in-memory'` for single-page applications, or + * `'session-storage'` for multi-page applications, which writes to the browser's `sessionStorage`. + * + * Default: 'in-memory' + */ + linkPreviousTrace?: 'in-memory' | 'session-storage'; + + /** + * If true, subsequent traces are sampled consistently with the sampling decision of the initial trace. + * + * Default: false + */ + consistentTraceSampling?: boolean; +} + +const _linkedTracesIntegration = ((options: LinkedTracesOptions = {}) => { + const { linkPreviousTrace = 'in-memory', consistentTraceSampling = false } = options; + + return { + name: 'LinkedTraces', + setup(client) { + linkTraces(client, { linkPreviousTrace, consistentTraceSampling }); + }, + }; +}) satisfies IntegrationFn; + +/** + * Links each new trace to the previous one, so you can navigate between traces in Sentry. + */ +export const linkedTracesIntegration = defineIntegration(_linkedTracesIntegration); diff --git a/packages/browser/src/tracing/browserTracingIntegration.ts b/packages/browser/src/tracing/browserTracingIntegration.ts index 5274d006b762..b7b27090f3ea 100644 --- a/packages/browser/src/tracing/browserTracingIntegration.ts +++ b/packages/browser/src/tracing/browserTracingIntegration.ts @@ -47,7 +47,7 @@ import { getHttpRequestData, WINDOW } from '../helpers'; import type { WebVitalsOptions } from '../integrations/webVitals'; import { webVitalsIntegration } from '../integrations/webVitals'; import { registerBackgroundTabDetection } from './backgroundtab'; -import { linkTraces } from './linkedTraces'; +import { linkedTracesIntegration } from '../integrations/linkedTraces'; import { xhrTracingIntegration } from '../integrations/xhrTracing'; import { defaultRequestInstrumentationOptions, instrumentFetchRequests } from './request'; import { @@ -287,7 +287,14 @@ export interface BrowserTracingOptions { */ export type BrowserTracingCoreOptions = Omit< BrowserTracingOptions, - 'enableInp' | 'webVitals' | 'enableElementTiming' | 'enableLongTask' | 'enableLongAnimationFrame' | 'traceXHR' + | 'enableInp' + | 'webVitals' + | 'enableElementTiming' + | 'enableLongTask' + | 'enableLongAnimationFrame' + | 'traceXHR' + | 'linkPreviousTrace' + | 'consistentTraceSampling' >; const DEFAULT_BROWSER_TRACING_OPTIONS: BrowserTracingCoreOptions = { @@ -298,8 +305,6 @@ const DEFAULT_BROWSER_TRACING_OPTIONS: BrowserTracingCoreOptions = { markBackgroundSpan: true, ignoreResourceSpans: [], detectRedirects: true, - linkPreviousTrace: 'in-memory', - consistentTraceSampling: false, enableReportPageLoaded: false, ...defaultRequestInstrumentationOptions, }; @@ -334,6 +339,8 @@ export const browserTracingIntegration = ((options: Partial { @@ -359,6 +366,10 @@ export const browserTracingIntegration = ((options: Partial { expect(!!client.getIntegrationByName('XhrTracing')).toBe(registered); }); + it.each([ + ['registers linkedTracesIntegration by default', {}, true], + [ + 'does not register linkedTracesIntegration when linkPreviousTrace is off', + { linkPreviousTrace: 'off' as const }, + false, + ], + ])('%s', (_name, options, registered) => { + const client = new BrowserClient( + getDefaultBrowserClientOptions({ + tracesSampleRate: 1, + integrations: [browserTracingIntegration(options)], + }), + ); + setCurrentClient(client); + client.init(); + + expect(!!client.getIntegrationByName('LinkedTraces')).toBe(registered); + }); + it('keeps the webVitalsIntegration the user supplies', () => { const userWebVitals = webVitalsModule.webVitalsIntegration({ softNavigations: false });