11import {
2+ SEMANTIC_ATTRIBUTE_SENTRY_OP ,
23 SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
34 SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ,
45 SPAN_STATUS_ERROR ,
@@ -19,42 +20,38 @@ import { platformSupportsStreaming } from './utils/platformSupportsStreaming';
1920import { flushQueue } from './utils/responseEnd' ;
2021import { withIsolationScopeOrReuseFromRootSpan } from './utils/withIsolationScopeOrReuseFromRootSpan' ;
2122
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 > ,
3028) : 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 ) ;
4831
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' ) ;
5637
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+ }
5855}
5956
6057/**
@@ -79,27 +76,35 @@ export function wrapRouteHandlerWithSentry<F extends (...args: any[]) => any>(
7976 } ) ;
8077
8178 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+ }
9995 } ,
100- async span => addSpanAttributes ( originalFunction , thisArg , args , span ) ,
10196 ) ;
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+ } ) ;
103108 } finally {
104109 if ( ! platformSupportsStreaming ( ) || process . env . NEXT_RUNTIME === 'edge' ) {
105110 // 1. Edge transport requires manual flushing
0 commit comments