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