11import {
2+ SEMANTIC_ATTRIBUTE_SENTRY_OP ,
23 SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
34 SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ,
45 SPAN_STATUS_ERROR ,
@@ -18,42 +19,38 @@ import type { RouteHandlerContext } from './types';
1819import { platformSupportsStreaming } from './utils/platformSupportsStreaming' ;
1920import { flushQueue } from './utils/responseEnd' ;
2021
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 > ,
2927) : 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 ) ;
4730
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' ) ;
5536
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+ }
5754}
5855
5956/**
@@ -78,27 +75,35 @@ export function wrapRouteHandlerWithSentry<F extends (...args: any[]) => any>(
7875 } ) ;
7976
8077 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+ }
9894 } ,
99- async span => addSpanAttributes ( originalFunction , thisArg , args , span ) ,
10095 ) ;
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+ } ) ;
102107 } finally {
103108 if ( ! platformSupportsStreaming ( ) || process . env . NEXT_RUNTIME === 'edge' ) {
104109 // 1. Edge transport requires manual flushing
0 commit comments