11import {
2- SEMANTIC_ATTRIBUTE_SENTRY_OP ,
3- SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
4- SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ,
5- SPAN_STATUS_ERROR ,
2+ Scope ,
63 captureException ,
4+ getActiveSpan ,
5+ getCapturedScopesOnSpan ,
6+ getRootSpan ,
77 handleCallbackErrors ,
8- setHttpStatus ,
9- startSpan ,
8+ setCapturedScopesOnSpan ,
109 withIsolationScope ,
1110 withScope ,
1211} from '@sentry/core' ;
13- import { propagationContextFromHeaders , winterCGHeadersToDict } from '@sentry/utils' ;
14- import { isNotFoundNavigationError , isRedirectNavigationError } from './nextNavigationErrorUtils' ;
12+
1513import 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' ;
2319
2420/**
2521 * 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>(
3430 const { method, parameterizedRoute, headers } = context ;
3531
3632 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 ) ;
4035
41- const completeHeadersDict : Record < string , string > = headers ? winterCGHeadersToDict ( headers ) : { } ;
36+ const completeHeadersDict : Record < string , string > = headers ? winterCGHeadersToDict ( headers ) : { } ;
4237
43- isolationScope . setSDKProcessingMetadata ( {
44- request : {
45- headers : completeHeadersDict ,
46- } ,
47- } ) ;
38+ isolationScope . setSDKProcessingMetadata ( {
39+ request : {
40+ headers : completeHeadersDict ,
41+ } ,
42+ } ) ;
4843
49- const incomingPropagationContext = propagationContextFromHeaders (
50- completeHeadersDict [ 'sentry-trace' ] ,
51- completeHeadersDict [ 'baggage' ] ,
52- ) ;
44+ const incomingPropagationContext = propagationContextFromHeaders (
45+ completeHeadersDict [ 'sentry-trace' ] ,
46+ completeHeadersDict [ 'baggage' ] ,
47+ ) ;
5348
54- const propagationContext = commonObjectToPropagationContext ( headers , incomingPropagationContext ) ;
49+ const propagationContext = commonObjectToPropagationContext ( headers , incomingPropagationContext ) ;
5550
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+ }
8958
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+ ) ;
10578 } ) ;
10679 } ) ;
10780 } ,
0 commit comments