@@ -149,15 +149,26 @@ export function sentryHandle(handlerOptions?: SentryHandleOptions): Handle {
149
149
} ;
150
150
151
151
const sentryRequestHandler : Handle = input => {
152
- // if there is an active span, we know that this handle call is nested and hence
153
- // we don't create a new execution context for it.
154
- // If we created one, nested server calls would create new root span instead
155
- // of adding a child span to the currently active span.
156
- if ( getActiveSpan ( ) ) {
152
+ // event.isSubRequest was added in SvelteKit 1.21.0 and we can use it to check
153
+ // if we should create a new execution context or not.
154
+ // In case of a same-origin `fetch` call within a server`load` function,
155
+ // SvelteKit will actually just re-enter the `handle` function and set `isSubRequest`
156
+ // to `true` so that no additional network call is made.
157
+ // We want the `http.server` span of that nested call to be a child span of the
158
+ // currently active span instead of a new root span to correctly reflect this
159
+ // behavior.
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
+
164
+ if ( isSubRequest ) {
157
165
return instrumentHandle ( input , options ) ;
158
166
}
167
+
159
168
return withIsolationScope ( ( ) => {
160
- 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 ) ) ;
161
172
} ) ;
162
173
} ;
163
174
@@ -172,36 +183,32 @@ async function instrumentHandle(
172
183
return resolve ( event ) ;
173
184
}
174
185
175
- const { sentryTrace, baggage } = getTracePropagationData ( event ) ;
176
-
177
- return continueTrace ( { sentryTrace, baggage } , async ( ) => {
178
- try {
179
- const resolveResult = await startSpan (
180
- {
181
- op : 'http.server' ,
182
- attributes : {
183
- [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.http.sveltekit' ,
184
- [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : event . route ?. id ? 'route' : 'url' ,
185
- 'http.method' : event . request . method ,
186
- } ,
187
- name : `${ event . request . method } ${ event . route ?. id || event . url . pathname } ` ,
188
- } ,
189
- async ( span ?: Span ) => {
190
- const res = await resolve ( event , {
191
- transformPageChunk : addSentryCodeToPage ( options ) ,
192
- } ) ;
193
- if ( span ) {
194
- setHttpStatus ( span , res . status ) ;
195
- }
196
- 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 ,
197
194
} ,
198
- ) ;
199
- return resolveResult ;
200
- } catch ( e : unknown ) {
201
- sendErrorToSentry ( e ) ;
202
- throw e ;
203
- } finally {
204
- await flushIfServerless ( ) ;
205
- }
206
- } ) ;
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
+ }
207
214
}
0 commit comments