Skip to content

Commit 91b0d28

Browse files
committed
avoid nested continueTrace calls
1 parent 3ebd3d4 commit 91b0d28

File tree

7 files changed

+63
-235
lines changed

7 files changed

+63
-235
lines changed
Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,17 @@
11
import { env } from '$env/dynamic/private';
22
import * as Sentry from '@sentry/sveltekit';
3-
import { sequence } from '@sveltejs/kit/hooks';
43

54
Sentry.init({
65
environment: 'qa', // dynamic sampling bias to keep transactions
76
dsn: env.E2E_TEST_DSN,
87
debug: true,
98
tunnel: `http://localhost:3031/`, // proxy server
109
tracesSampleRate: 1.0,
11-
beforeSendTransaction: txn => {
12-
// console.log('beforeSendTransaction', txn);
13-
return txn;
14-
},
1510
});
1611

1712
// not logging anything to console to avoid noise in the test output
1813
const myErrorHandler = ({ error, event }: any) => {};
1914

2015
export const handleError = Sentry.handleErrorWithSentry(myErrorHandler);
2116

22-
export const handle = sequence(async ({ event, resolve }) => {
23-
console.log('XX event issub', event.isSubRequest, Sentry.getActiveSpan());
24-
return resolve(event);
25-
}, Sentry.sentryHandle());
17+
export const handle = Sentry.sentryHandle();

dev-packages/e2e-tests/test-applications/sveltekit/test/performance.server.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ test('server pageload request span has nested request span', async ({ page }) =>
1212
const serverTxnEvent = await serverTxnEventPromise;
1313
const spans = serverTxnEvent.spans;
1414

15+
const outerHttpServerSpan = spans?.find(span => span.op === 'http.server' && span.description === 'GET /server-load-fetch');
16+
const innerHttpServerSpan = spans?.find(span => span.op === 'http.server' && span.description === 'GET /api/users');
17+
1518
expect(serverTxnEvent).toMatchObject({
1619
transaction: 'GET /server-load-fetch',
1720
tags: { runtime: 'node' },
@@ -25,7 +28,7 @@ test('server pageload request span has nested request span', async ({ page }) =>
2528
},
2629
});
2730

28-
console.log(JSON.stringify(spans, null, 2));
29-
3031
expect(spans).toHaveLength(3);
32+
expect(outerHttpServerSpan).toBeDefined();
33+
expect(innerHttpServerSpan).toBeDefined();
3134
});

packages/core/src/tracing/trace.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ export function startSpan<T>(context: StartSpanOptions, callback: (span: Span) =
5656
// eslint-disable-next-line deprecation/deprecation
5757
const parentSpan = scope.getSpan() as SentrySpan | undefined;
5858

59-
console.log(`xx startSpan ${context.op} ${context.name} parentSpan`, parentSpan);
60-
6159
const shouldSkipSpan = context.onlyIfParent && !parentSpan;
6260
const activeSpan = shouldSkipSpan
6361
? new SentryNonRecordingSpan()
@@ -253,7 +251,6 @@ function createChildSpanOrTransaction(
253251
span = parentSpan.startChild(spanContext);
254252
addChildSpanToSpan(parentSpan, span);
255253

256-
console.log('starting child span', spanContext.op);
257254
} else if (parentSpan) {
258255
// If we forced a transaction but have a parent span, make sure to continue from the parent span, not the scope
259256
const dsc = getDynamicSamplingContextFromSpan(parentSpan);
@@ -271,7 +268,6 @@ function createChildSpanOrTransaction(
271268
...spanContext.metadata,
272269
},
273270
});
274-
console.log('starting txn (forced)', spanContext.op);
275271
} else {
276272
const { traceId, dsc, parentSpanId, sampled } = {
277273
...isolationScope.getPropagationContext(),
@@ -289,7 +285,6 @@ function createChildSpanOrTransaction(
289285
...spanContext.metadata,
290286
},
291287
});
292-
console.log('starting txn', spanContext.op);
293288
}
294289

295290
// TODO v8: Technically `startTransaction` can return undefined, which is not reflected by the types

packages/sveltekit/src/server/handle.ts

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -157,25 +157,18 @@ export function sentryHandle(handlerOptions?: SentryHandleOptions): Handle {
157157
// We want the `http.server` span of that nested call to be a child span of the
158158
// currently active span instead of a new root span to correctly reflect this
159159
// behavior.
160-
// Type-casting to boolean | undefined to reflect that kit <1.21.0 doesn't have this property
161-
const isSubRequest = input.event.isSubRequest as boolean | undefined;
160+
// As a fallback for Kit < 1.21.0, we check if there is an active span only if there's none,
161+
// we create a new execution context.
162+
const isSubRequest = typeof input.event.isSubRequest === 'boolean' ? input.event.isSubRequest : !!getActiveSpan();
163+
162164
if (isSubRequest) {
163165
return instrumentHandle(input, options);
164166
}
165-
if (isSubRequest === false) {
166-
return withIsolationScope(() => instrumentHandle(input, options));
167-
}
168167

169-
// Fallback for Sveltekit < 1.21.0
170-
// if there is an active span, we know that this handle call is nested and hence
171-
// we don't create a new execution context for it.
172-
// If we created one, nested server calls would create new root span instead
173-
// of adding a child span to the currently active span.
174-
if (getActiveSpan()) {
175-
return instrumentHandle(input, options);
176-
}
177168
return withIsolationScope(() => {
178-
return instrumentHandle(input, options);
169+
// We only call continueTrace in the initial top level request to avoid
170+
// creating a new root span for the sub request.
171+
return continueTrace(getTracePropagationData(input.event), () => instrumentHandle(input, options));
179172
});
180173
};
181174

@@ -190,36 +183,32 @@ async function instrumentHandle(
190183
return resolve(event);
191184
}
192185

193-
const { sentryTrace, baggage } = getTracePropagationData(event);
194-
195-
return continueTrace({ sentryTrace, baggage }, async () => {
196-
try {
197-
const resolveResult = await startSpan(
198-
{
199-
op: 'http.server',
200-
attributes: {
201-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit',
202-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: event.route?.id ? 'route' : 'url',
203-
'http.method': event.request.method,
204-
},
205-
name: `${event.request.method} ${event.route?.id || event.url.pathname}`,
206-
},
207-
async (span?: Span) => {
208-
const res = await resolve(event, {
209-
transformPageChunk: addSentryCodeToPage(options),
210-
});
211-
if (span) {
212-
setHttpStatus(span, res.status);
213-
}
214-
return res;
186+
try {
187+
const resolveResult = await startSpan(
188+
{
189+
op: 'http.server',
190+
attributes: {
191+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit',
192+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: event.route?.id ? 'route' : 'url',
193+
'http.method': event.request.method,
215194
},
216-
);
217-
return resolveResult;
218-
} catch (e: unknown) {
219-
sendErrorToSentry(e);
220-
throw e;
221-
} finally {
222-
await flushIfServerless();
223-
}
224-
});
195+
name: `${event.request.method} ${event.route?.id || event.url.pathname}`,
196+
},
197+
async (span?: Span) => {
198+
const res = await resolve(event, {
199+
transformPageChunk: addSentryCodeToPage(options),
200+
});
201+
if (span) {
202+
setHttpStatus(span, res.status);
203+
}
204+
return res;
205+
},
206+
);
207+
return resolveResult;
208+
} catch (e: unknown) {
209+
sendErrorToSentry(e);
210+
throw e;
211+
} finally {
212+
await flushIfServerless();
213+
}
225214
}

packages/sveltekit/src/server/load.ts

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ import {
22
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
33
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
44
captureException,
5-
continueTrace,
65
startSpan,
76
} from '@sentry/node';
87
import { addNonEnumerableProperty, objectify } from '@sentry/utils';
98
import type { LoadEvent, ServerLoadEvent } from '@sveltejs/kit';
109

1110
import type { SentryWrappedFlag } from '../common/utils';
1211
import { isHttpError, isRedirect } from '../common/utils';
13-
import { flushIfServerless, getTracePropagationData } from './utils';
12+
import { flushIfServerless } from './utils';
1413

1514
type PatchedLoadEvent = LoadEvent & SentryWrappedFlag;
1615
type PatchedServerLoadEvent = ServerLoadEvent & SentryWrappedFlag;
@@ -132,30 +131,26 @@ export function wrapServerLoadWithSentry<T extends (...args: any) => any>(origSe
132131
// https://github.com/sveltejs/kit/blob/e133aba479fa9ba0e7f9e71512f5f937f0247e2c/packages/kit/src/runtime/server/page/load_data.js#L111C3-L124
133132
const routeId = event.route && (Object.getOwnPropertyDescriptor(event.route, 'id')?.value as string | undefined);
134133

135-
const { sentryTrace, baggage } = getTracePropagationData(event);
136-
137-
return continueTrace({ sentryTrace, baggage }, async () => {
138-
try {
139-
// We need to await before returning, otherwise we won't catch any errors thrown by the load function
140-
return await startSpan(
141-
{
142-
op: 'function.sveltekit.server.load',
143-
attributes: {
144-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit',
145-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeId ? 'route' : 'url',
146-
'http.method': event.request.method,
147-
},
148-
name: routeId ? routeId : event.url.pathname,
134+
try {
135+
// We need to await before returning, otherwise we won't catch any errors thrown by the load function
136+
return await startSpan(
137+
{
138+
op: 'function.sveltekit.server.load',
139+
attributes: {
140+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit',
141+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeId ? 'route' : 'url',
142+
'http.method': event.request.method,
149143
},
150-
() => wrappingTarget.apply(thisArg, args),
151-
);
152-
} catch (e: unknown) {
153-
sendErrorToSentry(e);
154-
throw e;
155-
} finally {
156-
await flushIfServerless();
157-
}
158-
});
144+
name: routeId ? routeId : event.url.pathname,
145+
},
146+
() => wrappingTarget.apply(thisArg, args),
147+
);
148+
} catch (e: unknown) {
149+
sendErrorToSentry(e);
150+
throw e;
151+
} finally {
152+
await flushIfServerless();
153+
}
159154
},
160155
});
161156
}

0 commit comments

Comments
 (0)