1- import  {  captureException ,  flush ,   getCurrentHub ,  startTransaction  }  from  '@sentry/node' ; 
1+ import  {  captureException ,  getCurrentHub ,  startTransaction  }  from  '@sentry/node' ; 
22import  {  extractTraceparentData ,  hasTracingEnabled  }  from  '@sentry/tracing' ; 
33import  { 
44  addExceptionMechanism , 
@@ -11,14 +11,8 @@ import {
1111import  *  as  domain  from  'domain' ; 
1212
1313import  {  formatAsCode ,  nextLogger  }  from  '../../utils/nextLogger' ; 
14- import  type  { 
15-   AugmentedNextApiRequest , 
16-   AugmentedNextApiResponse , 
17-   NextApiHandler , 
18-   ResponseEndMethod , 
19-   WrappedNextApiHandler , 
20-   WrappedResponseEndMethod , 
21- }  from  './types' ; 
14+ import  type  {  AugmentedNextApiRequest ,  AugmentedNextApiResponse ,  NextApiHandler ,  WrappedNextApiHandler  }  from  './types' ; 
15+ import  {  autoEndTransactionOnResponseEnd ,  finishTransaction ,  flushQueue  }  from  './utils/responseEnd' ; 
2216
2317/** 
2418 * Wrap the given API route handler for tracing and error capturing. Thin wrapper around `withSentry`, which only 
@@ -72,11 +66,6 @@ export function withSentry(origHandler: NextApiHandler, parameterizedRoute?: str
7266    } 
7367    req . __withSentry_applied__  =  true ; 
7468
75-     // first order of business: monkeypatch `res.end()` so that it will wait for us to send events to sentry before it 
76-     // fires (if we don't do this, the lambda will close too early and events will be either delayed or lost) 
77-     // eslint-disable-next-line @typescript-eslint/unbound-method 
78-     res . end  =  wrapEndMethod ( res . end ) ; 
79- 
8069    // use a domain in order to prevent scope bleed between requests 
8170    const  local  =  domain . create ( ) ; 
8271    local . add ( req ) ; 
@@ -137,9 +126,7 @@ export function withSentry(origHandler: NextApiHandler, parameterizedRoute?: str
137126          ) ; 
138127          currentScope . setSpan ( transaction ) ; 
139128
140-           // save a link to the transaction on the response, so that even if there's an error (landing us outside of 
141-           // the domain), we can still finish it (albeit possibly missing some scope data) 
142-           res . __sentryTransaction  =  transaction ; 
129+           autoEndTransactionOnResponseEnd ( transaction ,  res ) ; 
143130        } 
144131      } 
145132
@@ -189,7 +176,8 @@ export function withSentry(origHandler: NextApiHandler, parameterizedRoute?: str
189176        // out. (Apps which are deployed on Vercel run their API routes in lambdas, and those lambdas will shut down the 
190177        // moment they detect an error, so it's important to get this done before rethrowing the error. Apps not 
191178        // deployed serverlessly will run into this cleanup function again in `res.end(), but it'll just no-op.) 
192-         await  finishSentryProcessing ( res ) ; 
179+         await  finishTransaction ( res ) ; 
180+         await  flushQueue ( ) ; 
193181
194182        // We rethrow here so that nextjs can do with the error whatever it would normally do. (Sometimes "whatever it 
195183        // would normally do" is to allow the error to bubble up to the global handlers - another reason we need to mark 
@@ -203,57 +191,3 @@ export function withSentry(origHandler: NextApiHandler, parameterizedRoute?: str
203191    return  boundHandler ( ) ; 
204192  } ; 
205193} 
206- 
207- /** 
208-  * Wrap `res.end()` so that it closes the transaction and flushes events before letting the request finish. 
209-  * 
210-  * Note: This wraps a sync method with an async method. While in general that's not a great idea in terms of keeping 
211-  * things in the right order, in this case it's safe, because the native `.end()` actually *is* async, and its run 
212-  * actually *is* awaited, just manually so (which reflects the fact that the core of the request/response code in Node 
213-  * by far predates the introduction of `async`/`await`). When `.end()` is done, it emits the `prefinish` event, and 
214-  * only once that fires does request processing continue. See 
215-  * https://github.com/nodejs/node/commit/7c9b607048f13741173d397795bac37707405ba7. 
216-  * 
217-  * @param  origEnd The original `res.end()` method 
218-  * @returns  The wrapped version 
219-  */ 
220- function  wrapEndMethod ( origEnd : ResponseEndMethod ) : WrappedResponseEndMethod  { 
221-   return  async  function  newEnd ( this : AugmentedNextApiResponse ,  ...args : unknown [ ] )  { 
222-     await  finishSentryProcessing ( this ) ; 
223- 
224-     return  origEnd . call ( this ,  ...args ) ; 
225-   } ; 
226- } 
227- 
228- /** 
229-  * Close the open transaction (if any) and flush events to Sentry. 
230-  * 
231-  * @param  res The outgoing response for this request, on which the transaction is stored 
232-  */ 
233- async  function  finishSentryProcessing ( res : AugmentedNextApiResponse ) : Promise < void >  { 
234-   const  {  __sentryTransaction : transaction  }  =  res ; 
235- 
236-   if  ( transaction )  { 
237-     transaction . setHttpStatus ( res . statusCode ) ; 
238- 
239-     // Push `transaction.finish` to the next event loop so open spans have a better chance of finishing before the 
240-     // transaction closes, and make sure to wait until that's done before flushing events 
241-     const  transactionFinished : Promise < void >  =  new  Promise ( resolve  =>  { 
242-       setImmediate ( ( )  =>  { 
243-         transaction . finish ( ) ; 
244-         resolve ( ) ; 
245-       } ) ; 
246-     } ) ; 
247-     await  transactionFinished ; 
248-   } 
249- 
250-   // Flush the event queue to ensure that events get sent to Sentry before the response is finished and the lambda 
251-   // ends. If there was an error, rethrow it so that the normal exception-handling mechanisms can apply. 
252-   try  { 
253-     __DEBUG_BUILD__  &&  logger . log ( 'Flushing events...' ) ; 
254-     await  flush ( 2000 ) ; 
255-     __DEBUG_BUILD__  &&  logger . log ( 'Done flushing events' ) ; 
256-   }  catch  ( e )  { 
257-     __DEBUG_BUILD__  &&  logger . log ( 'Error while flushing events:\n' ,  e ) ; 
258-   } 
259- } 
0 commit comments