Skip to content

Commit 488e1e1

Browse files
committed
migrate
1 parent dbf1af1 commit 488e1e1

2 files changed

Lines changed: 163 additions & 37 deletions

File tree

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
import type { Integration, SpanJSON, SpanOrigin } from '@sentry/core';
2-
import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
1+
import type { Integration, SpanJSON, SpanOrigin, StreamedSpanJSON } from '@sentry/core';
2+
import {
3+
safeSetSpanJSONAttributes,
4+
SEMANTIC_ATTRIBUTE_SENTRY_OP,
5+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
6+
} from '@sentry/core';
37

48
/**
59
* A small integration that preprocesses spans so that SvelteKit-generated spans
@@ -20,6 +24,9 @@ export function svelteKitSpansIntegration(): Integration {
2024
event.spans?.forEach(_enhanceKitSpan);
2125
}
2226
},
27+
processSpan(span) {
28+
_enhanceKitSpanStreamed(span);
29+
},
2330
};
2431
}
2532

@@ -28,51 +35,63 @@ export function svelteKitSpansIntegration(): Integration {
2835
* @exported for testing
2936
*/
3037
export function _enhanceKitSpan(span: SpanJSON): void {
31-
let op: string | undefined = undefined;
32-
let origin: SpanOrigin | undefined = undefined;
33-
34-
const spanName = span.description;
38+
const { op, origin } = _getKitSpanEnhancement(span.description);
3539

3640
const previousOp = span.op || span.data[SEMANTIC_ATTRIBUTE_SENTRY_OP];
3741
const previousOrigin = span.origin || span.data[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN];
3842

43+
if (!previousOp && op) {
44+
span.op = op;
45+
span.data[SEMANTIC_ATTRIBUTE_SENTRY_OP] = op;
46+
}
47+
48+
if ((!previousOrigin || previousOrigin === 'manual') && origin) {
49+
span.origin = origin;
50+
span.data[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = origin;
51+
}
52+
}
53+
54+
/**
55+
* Streaming-mode counterpart of {@link _enhanceKitSpan} operating on {@link StreamedSpanJSON}.
56+
* @exported for testing
57+
*/
58+
export function _enhanceKitSpanStreamed(span: StreamedSpanJSON): void {
59+
const { op, origin } = _getKitSpanEnhancement(span.name);
60+
const previousOrigin = span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] as SpanOrigin | undefined;
61+
62+
if (op) {
63+
safeSetSpanJSONAttributes(span, { [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op });
64+
}
65+
66+
if (previousOrigin === 'manual' && origin) {
67+
// `safeSetSpanJSONAttributes` skips existing keys, so overwrite the 'manual' sentinel directly.
68+
span.attributes![SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = origin;
69+
} else {
70+
safeSetSpanJSONAttributes(span, { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin });
71+
}
72+
}
73+
74+
function _getKitSpanEnhancement(spanName: string | undefined): {
75+
op?: string;
76+
origin?: SpanOrigin;
77+
} {
3978
switch (spanName) {
4079
case 'sveltekit.resolve':
41-
op = 'function.sveltekit.resolve';
42-
origin = 'auto.http.sveltekit';
43-
break;
80+
return { op: 'function.sveltekit.resolve', origin: 'auto.http.sveltekit' };
4481
case 'sveltekit.load':
45-
op = 'function.sveltekit.load';
46-
origin = 'auto.function.sveltekit.load';
47-
break;
82+
return { op: 'function.sveltekit.load', origin: 'auto.function.sveltekit.load' };
4883
case 'sveltekit.form_action':
49-
op = 'function.sveltekit.form_action';
50-
origin = 'auto.function.sveltekit.action';
51-
break;
84+
return { op: 'function.sveltekit.form_action', origin: 'auto.function.sveltekit.action' };
5285
case 'sveltekit.remote.call':
53-
op = 'function.sveltekit.remote';
54-
origin = 'auto.rpc.sveltekit.remote';
55-
break;
86+
return { op: 'function.sveltekit.remote', origin: 'auto.rpc.sveltekit.remote' };
5687
case 'sveltekit.handle.root':
5788
// We don't want to overwrite the root handle span at this point since
5889
// we already enhance the root span in our `sentryHandle` hook.
59-
break;
60-
default: {
90+
return {};
91+
default:
6192
if (spanName?.startsWith('sveltekit.handle.sequenced.')) {
62-
op = 'function.sveltekit.handle';
63-
origin = 'auto.function.sveltekit.handle';
93+
return { op: 'function.sveltekit.handle', origin: 'auto.function.sveltekit.handle' };
6494
}
65-
break;
66-
}
67-
}
68-
69-
if (!previousOp && op) {
70-
span.op = op;
71-
span.data[SEMANTIC_ATTRIBUTE_SENTRY_OP] = op;
72-
}
73-
74-
if ((!previousOrigin || previousOrigin === 'manual') && origin) {
75-
span.origin = origin;
76-
span.data[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = origin;
95+
return {};
7796
}
7897
}

packages/sveltekit/test/server-common/integrations/svelteKitSpans.test.ts

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
import type { SpanJSON, TransactionEvent } from '@sentry/core';
1+
import type { SpanJSON, StreamedSpanJSON, TransactionEvent } from '@sentry/core';
22
import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
33
import { describe, expect, it } from 'vitest';
4-
import { _enhanceKitSpan, svelteKitSpansIntegration } from '../../../src/server-common/integrations/svelteKitSpans';
4+
import {
5+
_enhanceKitSpan,
6+
_enhanceKitSpanStreamed,
7+
svelteKitSpansIntegration,
8+
} from '../../../src/server-common/integrations/svelteKitSpans';
59

610
describe('svelteKitSpansIntegration', () => {
7-
it('has a name and a preprocessEventHook', () => {
11+
it('has a name and a preprocessEvent and processSpan hook', () => {
812
const integration = svelteKitSpansIntegration();
913

1014
expect(integration.name).toBe('SvelteKitSpansEnhancement');
1115
expect(typeof integration.preprocessEvent).toBe('function');
16+
expect(typeof integration.processSpan).toBe('function');
1217
});
1318

1419
it('enhances spans from SvelteKit', () => {
@@ -169,4 +174,106 @@ describe('svelteKitSpansIntegration', () => {
169174
expect(span.data[SEMANTIC_ATTRIBUTE_SENTRY_OP]).toBe('custom.op');
170175
});
171176
});
177+
178+
describe('_enhanceKitSpanStreamed', () => {
179+
function makeStreamedSpan(overrides: Partial<StreamedSpanJSON> = {}): StreamedSpanJSON {
180+
return {
181+
name: 'unspecified',
182+
span_id: '123',
183+
trace_id: 'abc',
184+
start_timestamp: 0,
185+
end_timestamp: 1,
186+
status: 'ok',
187+
is_segment: false,
188+
attributes: {},
189+
...overrides,
190+
};
191+
}
192+
193+
it.each([
194+
['sveltekit.resolve', 'function.sveltekit.resolve', 'auto.http.sveltekit'],
195+
['sveltekit.load', 'function.sveltekit.load', 'auto.function.sveltekit.load'],
196+
['sveltekit.form_action', 'function.sveltekit.form_action', 'auto.function.sveltekit.action'],
197+
['sveltekit.remote.call', 'function.sveltekit.remote', 'auto.rpc.sveltekit.remote'],
198+
['sveltekit.handle.sequenced.0', 'function.sveltekit.handle', 'auto.function.sveltekit.handle'],
199+
['sveltekit.handle.sequenced.myHandler', 'function.sveltekit.handle', 'auto.function.sveltekit.handle'],
200+
])('enhances %s span with the correct op and origin', (spanName, op, origin) => {
201+
const span = makeStreamedSpan({ name: spanName, attributes: { someAttribute: 'someValue' } });
202+
203+
_enhanceKitSpanStreamed(span);
204+
205+
expect(span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP]).toBe(op);
206+
expect(span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]).toBe(origin);
207+
});
208+
209+
it("doesn't change spans from other origins", () => {
210+
const span = makeStreamedSpan({ name: 'someOtherSpan' });
211+
212+
_enhanceKitSpanStreamed(span);
213+
214+
expect(span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP]).toBeUndefined();
215+
expect(span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]).toBeUndefined();
216+
});
217+
218+
it("doesn't overwrite the sveltekit.handle.root span", () => {
219+
const rootHandleSpan = makeStreamedSpan({
220+
name: 'sveltekit.handle.root',
221+
attributes: {
222+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',
223+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit',
224+
},
225+
});
226+
227+
_enhanceKitSpanStreamed(rootHandleSpan);
228+
229+
expect(rootHandleSpan.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP]).toBe('http.server');
230+
expect(rootHandleSpan.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]).toBe('auto.http.sveltekit');
231+
});
232+
233+
it("doesn't enhance unrelated spans", () => {
234+
const span = makeStreamedSpan({
235+
name: 'someOtherSpan',
236+
attributes: {
237+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db',
238+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.pg',
239+
},
240+
});
241+
242+
_enhanceKitSpanStreamed(span);
243+
244+
expect(span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP]).toBe('db');
245+
expect(span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]).toBe('auto.db.pg');
246+
});
247+
248+
it("doesn't overwrite already set ops or origins on sveltekit spans", () => {
249+
// for example, if users manually set this (for whatever reason)
250+
const span = makeStreamedSpan({
251+
name: 'sveltekit.resolve',
252+
attributes: {
253+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'custom.op',
254+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.custom.origin',
255+
},
256+
});
257+
258+
_enhanceKitSpanStreamed(span);
259+
260+
expect(span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP]).toBe('custom.op');
261+
expect(span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]).toBe('auto.custom.origin');
262+
});
263+
264+
it('overwrites previously set "manual" origins on sveltekit spans', () => {
265+
const span = makeStreamedSpan({
266+
name: 'sveltekit.resolve',
267+
attributes: {
268+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'custom.op',
269+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'manual',
270+
},
271+
});
272+
273+
_enhanceKitSpanStreamed(span);
274+
275+
expect(span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_OP]).toBe('custom.op');
276+
expect(span.attributes?.[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]).toBe('auto.http.sveltekit');
277+
});
278+
});
172279
});

0 commit comments

Comments
 (0)