1
1
import {
2
+ SEMANTIC_ATTRIBUTE_SENTRY_OP ,
2
3
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
3
4
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ,
4
5
SPAN_STATUS_ERROR ,
@@ -19,42 +20,38 @@ import { platformSupportsStreaming } from './utils/platformSupportsStreaming';
19
20
import { flushQueue } from './utils/responseEnd' ;
20
21
import { withIsolationScopeOrReuseFromRootSpan } from './utils/withIsolationScopeOrReuseFromRootSpan' ;
21
22
22
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
- async function addSpanAttributes < F extends ( ...args : any [ ] ) => any > (
24
- originalFunction : F ,
25
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
- thisArg : any ,
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
- args : any [ ] ,
29
- rootSpan ?: Span ,
23
+ /** As our own HTTP integration is disabled (src/server/index.ts) the rootSpan comes from Next.js.
24
+ * In case there is not root span, we start a new span. */
25
+ function startOrUpdateSpan (
26
+ spanName : string ,
27
+ handleResponseErrors : ( rootSpan : Span ) => Promise < Response > ,
30
28
) : Promise < Response > {
31
- const response : Response = await handleCallbackErrors (
32
- ( ) => originalFunction . apply ( thisArg , args ) ,
33
- error => {
34
- // Next.js throws errors when calling `redirect()`. We don't wanna report these.
35
- if ( isRedirectNavigationError ( error ) ) {
36
- // Don't do anything
37
- } else if ( isNotFoundNavigationError ( error ) && rootSpan ) {
38
- rootSpan . setStatus ( { code : SPAN_STATUS_ERROR , message : 'not_found' } ) ;
39
- } else {
40
- captureException ( error , {
41
- mechanism : {
42
- handled : false ,
43
- } ,
44
- } ) ;
45
- }
46
- } ,
47
- ) ;
29
+ const activeSpan = getActiveSpan ( ) ;
30
+ const rootSpan = activeSpan && getRootSpan ( activeSpan ) ;
48
31
49
- try {
50
- if ( rootSpan && response . status ) {
51
- setHttpStatus ( rootSpan , response . status ) ;
52
- }
53
- } catch {
54
- // best effort - response may be undefined?
55
- }
32
+ if ( rootSpan ) {
33
+ rootSpan . updateName ( spanName ) ;
34
+ rootSpan . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_SOURCE , 'route' ) ;
35
+ rootSpan . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_OP , 'http.server' ) ;
36
+ rootSpan . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN , 'auto.function.nextjs' ) ;
56
37
57
- return response ;
38
+ return handleResponseErrors ( rootSpan ) ;
39
+ } else {
40
+ return startSpan (
41
+ {
42
+ op : 'http.server' ,
43
+ name : spanName ,
44
+ forceTransaction : true ,
45
+ attributes : {
46
+ [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : 'route' ,
47
+ [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.function.nextjs' ,
48
+ } ,
49
+ } ,
50
+ ( span : Span ) => {
51
+ return handleResponseErrors ( span ) ;
52
+ } ,
53
+ ) ;
54
+ }
58
55
}
59
56
60
57
/**
@@ -79,27 +76,35 @@ export function wrapRouteHandlerWithSentry<F extends (...args: any[]) => any>(
79
76
} ) ;
80
77
81
78
try {
82
- const activeSpan = getActiveSpan ( ) ;
83
- const rootSpan = activeSpan && getRootSpan ( activeSpan ) ;
84
-
85
- if ( rootSpan ) {
86
- return await addSpanAttributes < F > ( originalFunction , thisArg , args , rootSpan ) ;
87
- } else {
88
- /** As our own HTTP integration is disabled (src/server/index.ts) the rootSpan comes from Next.js.
89
- * In case there is not root span, we start a new one. */
90
- return await startSpan (
91
- {
92
- op : 'http.server' ,
93
- name : `${ method } ${ parameterizedRoute } ` ,
94
- forceTransaction : true ,
95
- attributes : {
96
- [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : 'route' ,
97
- [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.function.nextjs' ,
98
- } ,
79
+ return await startOrUpdateSpan ( `${ method } ${ parameterizedRoute } ` , async ( rootSpan : Span ) => {
80
+ const response : Response = await handleCallbackErrors (
81
+ ( ) => originalFunction . apply ( thisArg , args ) ,
82
+ error => {
83
+ // Next.js throws errors when calling `redirect()`. We don't wanna report these.
84
+ if ( isRedirectNavigationError ( error ) ) {
85
+ // Don't do anything
86
+ } else if ( isNotFoundNavigationError ( error ) && rootSpan ) {
87
+ rootSpan . setStatus ( { code : SPAN_STATUS_ERROR , message : 'not_found' } ) ;
88
+ } else {
89
+ captureException ( error , {
90
+ mechanism : {
91
+ handled : false ,
92
+ } ,
93
+ } ) ;
94
+ }
99
95
} ,
100
- async span => addSpanAttributes ( originalFunction , thisArg , args , span ) ,
101
96
) ;
102
- }
97
+
98
+ try {
99
+ if ( rootSpan && response . status ) {
100
+ setHttpStatus ( rootSpan , response . status ) ;
101
+ }
102
+ } catch {
103
+ // best effort - response may be undefined?
104
+ }
105
+
106
+ return response ;
107
+ } ) ;
103
108
} finally {
104
109
if ( ! platformSupportsStreaming ( ) || process . env . NEXT_RUNTIME === 'edge' ) {
105
110
// 1. Edge transport requires manual flushing
0 commit comments