1
1
import {
2
- SEMANTIC_ATTRIBUTE_SENTRY_OP ,
3
- SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
4
- SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ,
5
- SPAN_STATUS_ERROR ,
2
+ Scope ,
6
3
captureException ,
4
+ getActiveSpan ,
5
+ getCapturedScopesOnSpan ,
6
+ getRootSpan ,
7
7
handleCallbackErrors ,
8
- setHttpStatus ,
9
- startSpan ,
8
+ setCapturedScopesOnSpan ,
10
9
withIsolationScope ,
11
10
withScope ,
12
11
} from '@sentry/core' ;
13
- import { propagationContextFromHeaders , winterCGHeadersToDict } from '@sentry/utils' ;
14
- import { isNotFoundNavigationError , isRedirectNavigationError } from './nextNavigationErrorUtils' ;
12
+
15
13
import type { RouteHandlerContext } from './types' ;
16
- import { flushSafelyWithTimeout } from './utils/responseEnd' ;
17
- import {
18
- commonObjectToIsolationScope ,
19
- commonObjectToPropagationContext ,
20
- escapeNextjsTracing ,
21
- } from './utils/tracingUtils' ;
22
- import { vercelWaitUntil } from './utils/vercelWaitUntil' ;
14
+
15
+ import { propagationContextFromHeaders , winterCGHeadersToDict } from '@sentry/utils' ;
16
+
17
+ import { isRedirectNavigationError } from './nextNavigationErrorUtils' ;
18
+ import { commonObjectToIsolationScope , commonObjectToPropagationContext } from './utils/tracingUtils' ;
23
19
24
20
/**
25
21
* Wraps a Next.js App Router Route handler with Sentry error and performance instrumentation.
@@ -34,74 +30,51 @@ export function wrapRouteHandlerWithSentry<F extends (...args: any[]) => any>(
34
30
const { method, parameterizedRoute, headers } = context ;
35
31
36
32
return new Proxy ( routeHandler , {
37
- apply : ( originalFunction , thisArg , args ) => {
38
- return escapeNextjsTracing ( ( ) => {
39
- const isolationScope = commonObjectToIsolationScope ( headers ) ;
33
+ apply : async ( originalFunction , thisArg , args ) => {
34
+ const isolationScope = commonObjectToIsolationScope ( headers ) ;
40
35
41
- const completeHeadersDict : Record < string , string > = headers ? winterCGHeadersToDict ( headers ) : { } ;
36
+ const completeHeadersDict : Record < string , string > = headers ? winterCGHeadersToDict ( headers ) : { } ;
42
37
43
- isolationScope . setSDKProcessingMetadata ( {
44
- request : {
45
- headers : completeHeadersDict ,
46
- } ,
47
- } ) ;
38
+ isolationScope . setSDKProcessingMetadata ( {
39
+ request : {
40
+ headers : completeHeadersDict ,
41
+ } ,
42
+ } ) ;
48
43
49
- const incomingPropagationContext = propagationContextFromHeaders (
50
- completeHeadersDict [ 'sentry-trace' ] ,
51
- completeHeadersDict [ 'baggage' ] ,
52
- ) ;
44
+ const incomingPropagationContext = propagationContextFromHeaders (
45
+ completeHeadersDict [ 'sentry-trace' ] ,
46
+ completeHeadersDict [ 'baggage' ] ,
47
+ ) ;
53
48
54
- const propagationContext = commonObjectToPropagationContext ( headers , incomingPropagationContext ) ;
49
+ const propagationContext = commonObjectToPropagationContext ( headers , incomingPropagationContext ) ;
55
50
56
- return withIsolationScope ( isolationScope , ( ) => {
57
- return withScope ( async scope => {
58
- scope . setTransactionName ( `${ method } ${ parameterizedRoute } ` ) ;
59
- scope . setPropagationContext ( propagationContext ) ;
60
- try {
61
- return startSpan (
62
- {
63
- name : `${ method } ${ parameterizedRoute } ` ,
64
- attributes : {
65
- [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : 'route' ,
66
- [ SEMANTIC_ATTRIBUTE_SENTRY_OP ] : 'http.server' ,
67
- [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.function.nextjs' ,
68
- } ,
69
- forceTransaction : true ,
70
- } ,
71
- async span => {
72
- const response : Response = await handleCallbackErrors (
73
- ( ) => originalFunction . apply ( thisArg , args ) ,
74
- error => {
75
- // Next.js throws errors when calling `redirect()`. We don't wanna report these.
76
- if ( isRedirectNavigationError ( error ) ) {
77
- // Don't do anything
78
- } else if ( isNotFoundNavigationError ( error ) && span ) {
79
- span . setStatus ( { code : SPAN_STATUS_ERROR , message : 'not_found' } ) ;
80
- } else {
81
- captureException ( error , {
82
- mechanism : {
83
- handled : false ,
84
- } ,
85
- } ) ;
86
- }
87
- } ,
88
- ) ;
51
+ const activeSpan = getActiveSpan ( ) ;
52
+ if ( activeSpan ) {
53
+ const rootSpan = getRootSpan ( activeSpan ) ;
54
+ rootSpan . setAttribute ( 'sentry.route_handler' , true ) ;
55
+ const { scope } = getCapturedScopesOnSpan ( rootSpan ) ;
56
+ setCapturedScopesOnSpan ( rootSpan , scope ?? new Scope ( ) , isolationScope ) ;
57
+ }
89
58
90
- try {
91
- if ( span && response . status ) {
92
- setHttpStatus ( span , response . status ) ;
93
- }
94
- } catch {
95
- // best effort - response may be undefined?
96
- }
97
-
98
- return response ;
99
- } ,
100
- ) ;
101
- } finally {
102
- vercelWaitUntil ( flushSafelyWithTimeout ( ) ) ;
103
- }
104
- } ) ;
59
+ return withIsolationScope ( isolationScope , ( ) => {
60
+ return withScope ( scope => {
61
+ scope . setTransactionName ( `${ method } ${ parameterizedRoute } ` ) ;
62
+ scope . setPropagationContext ( propagationContext ) ;
63
+ return handleCallbackErrors (
64
+ ( ) => originalFunction . apply ( thisArg , args ) ,
65
+ error => {
66
+ // Next.js throws errors when calling `redirect()`. We don't wanna report these.
67
+ if ( isRedirectNavigationError ( error ) ) {
68
+ // Don't do anything
69
+ } else {
70
+ captureException ( error , {
71
+ mechanism : {
72
+ handled : false ,
73
+ } ,
74
+ } ) ;
75
+ }
76
+ } ,
77
+ ) ;
105
78
} ) ;
106
79
} ) ;
107
80
} ,
0 commit comments