Skip to content

Commit 4cba0db

Browse files
committed
fix(core): Fix withStreamedSpan typing error and export from SDKs
1 parent 595985b commit 4cba0db

File tree

34 files changed

+186
-9
lines changed

34 files changed

+186
-9
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
7+
integrations: [Sentry.browserTracingIntegration(), Sentry.spanStreamingIntegration()],
8+
tracesSampleRate: 1,
9+
beforeSendSpan: Sentry.withStreamedSpan(span => {
10+
if (span.attributes['sentry.op'] === 'pageload') {
11+
span.name = 'customPageloadSpanName';
12+
span.links = [
13+
{
14+
context: {
15+
traceId: '123',
16+
spanId: '456',
17+
},
18+
attributes: {
19+
'sentry.link.type': 'custom_link',
20+
},
21+
},
22+
];
23+
span.attributes['sentry.custom_attribute'] = 'customAttributeValue';
24+
span.status = 'something'
25+
}
26+
return span;
27+
}),
28+
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { expect } from '@playwright/test';
2+
import { sentryTest } from '../../../utils/fixtures';
3+
import { shouldSkipTracingTest, testingCdnBundle } from '../../../utils/helpers';
4+
import { getSpanOp, waitForStreamedSpan } from '../../../utils/spanUtils';
5+
6+
sentryTest('beforeSendSpan applies changes to streamed span', async ({ getLocalTestUrl, page }) => {
7+
sentryTest.skip(shouldSkipTracingTest() || testingCdnBundle());
8+
9+
const url = await getLocalTestUrl({ testDir: __dirname });
10+
11+
const pageloadSpanPromise = waitForStreamedSpan(page, span => getSpanOp(span) === 'pageload');
12+
13+
await page.goto(url);
14+
15+
const pageloadSpan = await pageloadSpanPromise;
16+
17+
expect(pageloadSpan.name).toBe('customPageloadSpanName');
18+
expect(pageloadSpan.links).toEqual([
19+
{
20+
context: {
21+
traceId: '123',
22+
spanId: '456',
23+
},
24+
attributes: {
25+
'sentry.link.type': { type: 'string', value: 'custom_link' },
26+
},
27+
},
28+
]);
29+
expect(pageloadSpan.attributes?.['sentry.custom_attribute']).toEqual({
30+
type: 'string',
31+
value: 'customAttributeValue',
32+
});
33+
// we allow overriding any kinds of fields on the span, so we have to expect invalid values
34+
expect(pageloadSpan.status).toBe('something');
35+
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import * as Sentry from '@sentry/node-core';
2+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
3+
import { setupOtel } from '../../../utils/setupOtel';
4+
5+
const client = Sentry.init({
6+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
7+
tracesSampleRate: 1.0,
8+
traceLifecycle: 'stream',
9+
transport: loggingTransport,
10+
release: '1.0.0',
11+
beforeSendSpan: Sentry.withStreamedSpan(span => {
12+
if (span.name === 'test-child-span') {
13+
span.name = 'customChildSpanName';
14+
if (!span.attributes) {
15+
span.attributes = {};
16+
}
17+
span.attributes['sentry.custom_attribute'] = 'customAttributeValue';
18+
// oxlint-disable-next-line typescript/ban-ts-comment
19+
// @ts-expect-error - technically this is something we have to expect, despite types saying it's invalid
20+
span.status = 'something';
21+
span.links = [
22+
{
23+
trace_id: '123',
24+
span_id: '456',
25+
attributes: {
26+
'sentry.link.type': 'custom_link',
27+
},
28+
},
29+
];
30+
}
31+
return span;
32+
}),
33+
});
34+
35+
setupOtel(client);
36+
37+
Sentry.startSpan({ name: 'test-span', op: 'test' }, () => {
38+
Sentry.startSpan({ name: 'test-child-span', op: 'test-child' }, () => {
39+
// noop
40+
});
41+
});
42+
43+
void Sentry.flush();
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { expect, test } from 'vitest';
2+
import { createRunner } from '../../../utils/runner';
3+
4+
test('beforeSendSpan applies changes to streamed span', async () => {
5+
await createRunner(__dirname, 'scenario.ts')
6+
.expect({
7+
span: container => {
8+
const spans = container.items;
9+
expect(spans.length).toBe(2);
10+
11+
const customChildSpan = spans.find(s => s.name === 'customChildSpanName');
12+
13+
expect(customChildSpan).toBeDefined();
14+
expect(customChildSpan!.attributes?.['sentry.custom_attribute']).toEqual({
15+
type: 'string',
16+
value: 'customAttributeValue',
17+
});
18+
expect(customChildSpan!.status).toBe('something');
19+
expect(customChildSpan!.links).toEqual([
20+
{
21+
trace_id: '123',
22+
span_id: '456',
23+
attributes: {
24+
'sentry.link.type': { type: 'string', value: 'custom_link' },
25+
},
26+
},
27+
]);
28+
},
29+
})
30+
.start()
31+
.completed();
32+
});

packages/angular/src/sdk.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,11 @@ function checkAndSetAngularVersion(): void {
8282
setContext('angular', { version: angularVersion });
8383
}
8484
}
85+
86+
init({
87+
dsn: '__DSN__',
88+
traceLifecycle: 'stream',
89+
beforeSendSpan: span => {
90+
return span;
91+
},
92+
});

packages/astro/src/index.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ export {
174174
unleashIntegration,
175175
growthbookIntegration,
176176
spanStreamingIntegration,
177+
withStreamedSpan,
177178
metrics,
178179
} from '@sentry/node';
179180

packages/astro/src/index.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export declare function init(options: Options | clientSdk.BrowserOptions | NodeO
2121
export declare const linkedErrorsIntegration: typeof clientSdk.linkedErrorsIntegration;
2222
export declare const contextLinesIntegration: typeof clientSdk.contextLinesIntegration;
2323
export declare const spanStreamingIntegration: typeof clientSdk.spanStreamingIntegration;
24+
export declare const withStreamedSpan: typeof clientSdk.withStreamedSpan;
2425

2526
export declare const getDefaultIntegrations: (options: Options) => Integration[];
2627
export declare const defaultStackParser: StackParser;

packages/aws-serverless/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ export {
161161
growthbookIntegration,
162162
metrics,
163163
spanStreamingIntegration,
164+
withStreamedSpan,
164165
} from '@sentry/node';
165166

166167
export {

packages/browser/src/exports.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export {
7070
spanToTraceHeader,
7171
spanToBaggageHeader,
7272
updateSpanName,
73+
withStreamedSpan,
7374
metrics,
7475
} from '@sentry/core';
7576

packages/browser/src/integrations/spanstreaming.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const spanStreamingIntegration = defineIntegration(() => {
1919
// This avoids the classic double-opt-in problem we'd otherwise have in the browser SDK.
2020
const clientOptions = client.getOptions();
2121
if (!clientOptions.traceLifecycle) {
22-
DEBUG_BUILD && debug.warn('[SpanStreaming] set `traceLifecycle` to "stream"');
22+
DEBUG_BUILD && debug.log('[SpanStreaming] set `traceLifecycle` to "stream"');
2323
clientOptions.traceLifecycle = 'stream';
2424
}
2525
},

0 commit comments

Comments
 (0)