1
1
import { captureException , flush , getCurrentHub , Handlers , startTransaction , withScope } from '@sentry/node' ;
2
2
import { extractTraceparentData , getActiveTransaction , hasTracingEnabled } from '@sentry/tracing' ;
3
3
import { addExceptionMechanism , isString , logger , stripUrlQueryAndFragment } from '@sentry/utils' ;
4
- import { NextApiHandler } from 'next' ;
4
+ import { NextApiHandler , NextApiResponse } from 'next' ;
5
5
6
6
import { addRequestDataToEvent , NextRequest } from './instrumentServer' ;
7
7
@@ -51,6 +51,8 @@ export const withSentry = (handler: NextApiHandler): WrappedNextApiHandler => {
51
51
{ request : req } ,
52
52
) ;
53
53
currentScope . setSpan ( transaction ) ;
54
+
55
+ res . on ( 'finish' , async ( ) => await finishTransaction ( res ) ) ;
54
56
}
55
57
}
56
58
@@ -65,19 +67,44 @@ export const withSentry = (handler: NextApiHandler): WrappedNextApiHandler => {
65
67
} ) ;
66
68
captureException ( e ) ;
67
69
} ) ;
70
+ await finishTransaction ( res ) ;
68
71
throw e ;
69
- } finally {
70
- const transaction = getActiveTransaction ( ) ;
71
- if ( transaction ) {
72
- transaction . setHttpStatus ( res . statusCode ) ;
72
+ }
73
+ } ;
74
+ } ;
73
75
74
- transaction . finish ( ) ;
75
- }
76
+ async function finishTransaction ( res : NextApiResponse ) : Promise < void > {
77
+ const transaction = getActiveTransaction ( ) ;
78
+
79
+ if ( ! transaction ) {
80
+ // nothing to do
81
+ return Promise . resolve ( ) ;
82
+ }
83
+
84
+ // now that we have the transaction, pop it off of the scope so it doesn't affect future requests
85
+ // TODO use domains?
86
+ getCurrentHub ( )
87
+ . getScope ( )
88
+ ?. setSpan ( undefined ) ;
89
+
90
+ transaction . setHttpStatus ( res . statusCode ) ;
91
+
92
+ const finishPromise = new Promise < void > ( ( resolve , reject ) => {
93
+ // Push `transaction.finish` to the next event loop so open spans have a chance to finish before the
94
+ // transaction closes
95
+ setImmediate ( async ( ) => {
96
+ transaction . finish ( ) ;
76
97
try {
98
+ logger . log ( 'Flushing event buffer' ) ;
77
99
await flush ( 2000 ) ;
78
- } catch ( e ) {
79
- // no-empty
100
+ logger . log ( 'Buffer flushed' ) ;
101
+ resolve ( ) ;
102
+ } catch ( err ) {
103
+ logger . log ( 'Error while flushing buffer:' , err ) ;
104
+ reject ( err ) ;
80
105
}
81
- }
82
- } ;
83
- } ;
106
+ } ) ;
107
+ } ) ;
108
+
109
+ return finishPromise ;
110
+ }
0 commit comments