5
5
runWithAsyncContext ,
6
6
startTransaction ,
7
7
} from '@sentry/core' ;
8
- import type { Transaction } from '@sentry/types' ;
8
+ import type { Span , Transaction } from '@sentry/types' ;
9
9
import { baggageHeaderToDynamicSamplingContext , extractTraceparentData } from '@sentry/utils' ;
10
10
import type { IncomingMessage , ServerResponse } from 'http' ;
11
11
@@ -82,7 +82,8 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
82
82
return async function ( this : unknown , ...args : Parameters < F > ) : Promise < ReturnType < F > > {
83
83
return runWithAsyncContext ( async ( ) => {
84
84
const hub = getCurrentHub ( ) ;
85
- let requestTransaction : Transaction | undefined = getTransactionFromRequest ( req ) ;
85
+ const scope = hub . getScope ( ) ;
86
+ const previousSpan : Span | undefined = getTransactionFromRequest ( req ) ?? scope . getSpan ( ) ;
86
87
let dataFetcherSpan ;
87
88
88
89
const sentryTraceHeader = req . headers [ 'sentry-trace' ] ;
@@ -93,7 +94,8 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
93
94
const dynamicSamplingContext = baggageHeaderToDynamicSamplingContext ( rawBaggageString ) ;
94
95
95
96
if ( platformSupportsStreaming ( ) ) {
96
- if ( requestTransaction === undefined ) {
97
+ let spanToContinue : Span ;
98
+ if ( previousSpan === undefined ) {
97
99
const newTransaction = startTransaction (
98
100
{
99
101
op : 'http.server' ,
@@ -109,8 +111,6 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
109
111
{ request : req } ,
110
112
) ;
111
113
112
- requestTransaction = newTransaction ;
113
-
114
114
if ( platformSupportsStreaming ( ) ) {
115
115
// On platforms that don't support streaming, doing things after res.end() is unreliable.
116
116
autoEndTransactionOnResponseEnd ( newTransaction , res ) ;
@@ -119,9 +119,12 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
119
119
// Link the transaction and the request together, so that when we would normally only have access to one, it's
120
120
// still possible to grab the other.
121
121
setTransactionOnRequest ( newTransaction , req ) ;
122
+ spanToContinue = newTransaction ;
123
+ } else {
124
+ spanToContinue = previousSpan ;
122
125
}
123
126
124
- dataFetcherSpan = requestTransaction . startChild ( {
127
+ dataFetcherSpan = spanToContinue . startChild ( {
125
128
op : 'function.nextjs' ,
126
129
description : `${ options . dataFetchingMethodName } (${ options . dataFetcherRouteName } )` ,
127
130
status : 'ok' ,
@@ -140,22 +143,20 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
140
143
} ) ;
141
144
}
142
145
143
- const currentScope = hub . getScope ( ) ;
144
- if ( currentScope ) {
145
- currentScope . setSpan ( dataFetcherSpan ) ;
146
- currentScope . setSDKProcessingMetadata ( { request : req } ) ;
147
- }
146
+ scope . setSpan ( dataFetcherSpan ) ;
147
+ scope . setSDKProcessingMetadata ( { request : req } ) ;
148
148
149
149
try {
150
150
return await origDataFetcher . apply ( this , args ) ;
151
151
} catch ( e ) {
152
152
// Since we finish the span before the error can bubble up and trigger the handlers in `registerErrorInstrumentation`
153
153
// that set the transaction status, we need to manually set the status of the span & transaction
154
154
dataFetcherSpan . setStatus ( 'internal_error' ) ;
155
- requestTransaction ?. setStatus ( 'internal_error' ) ;
155
+ previousSpan ?. setStatus ( 'internal_error' ) ;
156
156
throw e ;
157
157
} finally {
158
158
dataFetcherSpan . finish ( ) ;
159
+ scope . setSpan ( previousSpan ) ;
159
160
if ( ! platformSupportsStreaming ( ) ) {
160
161
await flushQueue ( ) ;
161
162
}
0 commit comments