Skip to content

Commit bf07f9b

Browse files
Lms24cursoragent
andcommitted
feat(core)!: Enable span streaming by default
Default clients to the streamed trace lifecycle and automatically install the required streaming integration in browser and server runtimes. Explicit static lifecycle configuration remains supported. BREAKING CHANGE: Spans use the streamed trace lifecycle unless configured otherwise. Fixes #22344 Co-Authored-By: Cursor <cursoragent@cursor.com>
1 parent 3097b9c commit bf07f9b

32 files changed

Lines changed: 142 additions & 34 deletions

packages/browser/src/sdk.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { globalHandlersIntegration } from './integrations/globalhandlers';
1919
import { httpContextIntegration } from './integrations/httpcontext';
2020
import { linkedErrorsIntegration } from './integrations/linkederrors';
2121
import { spotlightBrowserIntegration } from './integrations/spotlight';
22+
import { spanStreamingIntegration } from './integrations/spanstreaming';
2223
import { defaultStackParser } from './stack-parsers';
2324
import { makeFetchTransport } from './transports/fetch';
2425
import { normalizeStringifyValue } from './normalizeStringifyValue';
@@ -110,14 +111,20 @@ export function init(options: BrowserOptions = {}): Client | undefined {
110111
}
111112
/*! rollup-include-development-only-end */
112113

114+
const integrations = getIntegrationsToSetup({
115+
integrations: options.integrations,
116+
defaultIntegrations,
117+
});
118+
119+
if (options.traceLifecycle !== 'static' && !integrations.some(integration => integration.name === 'SpanStreaming')) {
120+
integrations.push(spanStreamingIntegration());
121+
}
122+
113123
const clientOptions: BrowserClientOptions = {
114124
...options,
115125
enabled: shouldDisableBecauseIsBrowserExtenstion ? false : options.enabled,
116126
stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),
117-
integrations: getIntegrationsToSetup({
118-
integrations: options.integrations,
119-
defaultIntegrations,
120-
}),
127+
integrations,
121128
transport: options.transport || makeFetchTransport,
122129
};
123130

packages/browser/test/profiling/UIProfiler.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ function getBaseOptionsForTraceLifecycle(sendMock: Mock<any>, enableTracing = tr
1111
return {
1212
dsn: 'https://public@o.ingest.sentry.io/1',
1313
...(enableTracing ? { tracesSampleRate: 1 } : {}),
14+
traceLifecycle: 'static',
1415
profileSessionSampleRate: 1,
1516
profileLifecycle: 'trace',
1617
integrations: [Sentry.browserProfilingIntegration()],
@@ -711,6 +712,7 @@ function getBaseOptionsForManualLifecycle(sendMock: Mock<any>, enableTracing = t
711712
return {
712713
dsn: 'https://public@o.ingest.sentry.io/1',
713714
...(enableTracing ? { tracesSampleRate: 1 } : {}),
715+
traceLifecycle: 'static',
714716
profileSessionSampleRate: 1,
715717
profileLifecycle: 'manual',
716718
integrations: [Sentry.browserProfilingIntegration()],

packages/browser/test/profiling/integration.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ describe('BrowserProfilingIntegration', () => {
3939
const send = vi.fn().mockImplementation(() => Promise.resolve());
4040
const client = Sentry.init({
4141
tracesSampleRate: 1,
42+
traceLifecycle: 'static',
4243
profilesSampleRate: 1,
4344
environment: 'test-environment',
4445
dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302',
@@ -134,6 +135,7 @@ describe('BrowserProfilingIntegration', () => {
134135
const send = vi.fn().mockResolvedValue(undefined);
135136
const client = Sentry.init({
136137
tracesSampleRate: 1,
138+
traceLifecycle: 'static',
137139
profilesSampleRate: 1,
138140
dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302',
139141
transport: _opts => ({

packages/browser/test/sdk.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,32 @@ describe('init', () => {
6161
expect(optionsPassed?.integrations.length).toBeGreaterThan(0);
6262
});
6363

64+
it('installs spanStreamingIntegration by default', () => {
65+
// @ts-expect-error this is fine for testing
66+
const initAndBindSpy = vi.spyOn(SentryCore, 'initAndBind').mockImplementationOnce(() => {});
67+
const options = getDefaultBrowserOptions({ dsn: PUBLIC_DSN, defaultIntegrations: undefined });
68+
69+
init(options);
70+
71+
const optionsPassed = initAndBindSpy.mock.calls[0]?.[1];
72+
expect(optionsPassed?.integrations.some(integration => integration.name === 'SpanStreaming')).toBe(true);
73+
});
74+
75+
it('does not install spanStreamingIntegration when traceLifecycle is static', () => {
76+
// @ts-expect-error this is fine for testing
77+
const initAndBindSpy = vi.spyOn(SentryCore, 'initAndBind').mockImplementationOnce(() => {});
78+
const options = getDefaultBrowserOptions({
79+
dsn: PUBLIC_DSN,
80+
defaultIntegrations: undefined,
81+
traceLifecycle: 'static',
82+
});
83+
84+
init(options);
85+
86+
const optionsPassed = initAndBindSpy.mock.calls[0]?.[1];
87+
expect(optionsPassed?.integrations.some(integration => integration.name === 'SpanStreaming')).toBe(false);
88+
});
89+
6490
test("doesn't install default integrations if told not to", () => {
6591
const DEFAULT_INTEGRATIONS: Integration[] = [
6692
new MockIntegration('MockIntegration 0.3'),
@@ -73,6 +99,17 @@ describe('init', () => {
7399
expect(DEFAULT_INTEGRATIONS[1]!.setupOnce as Mock).toHaveBeenCalledTimes(0);
74100
});
75101

102+
it('installs spanStreamingIntegration with defaultIntegrations disabled', () => {
103+
// @ts-expect-error this is fine for testing
104+
const initAndBindSpy = vi.spyOn(SentryCore, 'initAndBind').mockImplementationOnce(() => {});
105+
const options = getDefaultBrowserOptions({ dsn: PUBLIC_DSN, defaultIntegrations: false });
106+
107+
init(options);
108+
109+
const optionsPassed = initAndBindSpy.mock.calls[0]?.[1];
110+
expect(optionsPassed?.integrations.some(integration => integration.name === 'SpanStreaming')).toBe(true);
111+
});
112+
76113
it('installs merged default integrations, with overrides provided through options', () => {
77114
const DEFAULT_INTEGRATIONS = [
78115
new MockIntegration('MockIntegration 1.1'),

packages/bun/test/init.test.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe('init()', () => {
3535

3636
describe('integrations', () => {
3737
it("doesn't install default integrations if told not to", () => {
38-
init({ dsn: PUBLIC_DSN, defaultIntegrations: false });
38+
init({ dsn: PUBLIC_DSN, defaultIntegrations: false, traceLifecycle: 'static' });
3939

4040
const client = getClient();
4141

@@ -132,7 +132,7 @@ describe('init()', () => {
132132

133133
describe('initWithoutDefaultIntegrations()', () => {
134134
it('installs no default integrations', () => {
135-
initWithoutDefaultIntegrations({ dsn: PUBLIC_DSN });
135+
initWithoutDefaultIntegrations({ dsn: PUBLIC_DSN, traceLifecycle: 'static' });
136136

137137
const client = getClient();
138138

@@ -143,7 +143,11 @@ describe('init()', () => {
143143
it('still installs user-provided integrations', () => {
144144
const customIntegration = new MockIntegration('Custom integration');
145145

146-
initWithoutDefaultIntegrations({ dsn: PUBLIC_DSN, integrations: [customIntegration] });
146+
initWithoutDefaultIntegrations({
147+
dsn: PUBLIC_DSN,
148+
integrations: [customIntegration],
149+
traceLifecycle: 'static',
150+
});
147151

148152
const client = getClient();
149153

packages/bundler-plugins/src/core/sentry/telemetry.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export function createSentryInstance(
2727
dsn: 'https://4c2bae7d9fbc413e8f7385f55c515d51@o1.ingest.sentry.io/6690737',
2828

2929
tracesSampleRate: 1,
30+
traceLifecycle: 'static',
3031
sampleRate: 1,
3132

3233
release: LIB_VERSION,

packages/cloudflare/test/instrumentations/worker/instrumentEmail.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ describe('instrumentEmail', () => {
245245
env => ({
246246
dsn: env.SENTRY_DSN,
247247
tracesSampleRate: 1,
248+
traceLifecycle: 'static',
248249
beforeSendTransaction(event) {
249250
sentryEvent = event;
250251
return null;

packages/cloudflare/test/instrumentations/worker/instrumentQueue.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ describe('instrumentQueue', () => {
258258
env => ({
259259
dsn: env.SENTRY_DSN,
260260
tracesSampleRate: 1,
261+
traceLifecycle: 'static',
261262
beforeSendTransaction(event) {
262263
sentryEvent = event;
263264
return null;

packages/cloudflare/test/instrumentations/worker/instrumentScheduled.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ describe('instrumentScheduled', () => {
240240
env => ({
241241
dsn: env.SENTRY_DSN,
242242
tracesSampleRate: 1,
243+
traceLifecycle: 'static',
243244
beforeSendTransaction(event) {
244245
sentryEvent = event;
245246
return null;

packages/cloudflare/test/opentelemetry.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ describe('opentelemetry compatibility', () => {
1616
const client = init({
1717
dsn: 'https://username@domain/123',
1818
tracesSampleRate: 1,
19+
traceLifecycle: 'static',
1920
skipOpenTelemetrySetup: true,
2021
beforeSendTransaction: event => {
2122
transactionEvents.push(event);
@@ -46,6 +47,7 @@ describe('opentelemetry compatibility', () => {
4647
const client = init({
4748
dsn: 'https://username@domain/123',
4849
tracesSampleRate: 1,
50+
traceLifecycle: 'static',
4951
beforeSendTransaction: event => {
5052
transactionEvents.push(event);
5153
return null;
@@ -106,6 +108,7 @@ describe('opentelemetry compatibility', () => {
106108
const client = init({
107109
dsn: 'https://username@domain/123',
108110
tracesSampleRate: 1,
111+
traceLifecycle: 'static',
109112
beforeSendTransaction: event => {
110113
transactionEvents.push(event);
111114
return null;
@@ -149,6 +152,7 @@ describe('opentelemetry compatibility', () => {
149152
const client = init({
150153
dsn: 'https://username@domain/123',
151154
tracesSampleRate: 1,
155+
traceLifecycle: 'static',
152156
beforeSendTransaction: event => {
153157
transactionEvents.push(event);
154158
return null;
@@ -176,6 +180,7 @@ describe('opentelemetry compatibility', () => {
176180
const client = init({
177181
dsn: 'https://username@domain/123',
178182
tracesSampleRate: 1,
183+
traceLifecycle: 'static',
179184
beforeSendTransaction: event => {
180185
transactionEvents.push(event);
181186
return null;

0 commit comments

Comments
 (0)