1- import type { TransactionSource } from '@sentry/core' ;
21import {
32 captureException ,
43 getActiveSpan ,
54 getCurrentScope ,
65 getRootSpan ,
76 handleCallbackErrors ,
8- SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
9- SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ,
107 setCapturedScopesOnSpan ,
11- startSpan ,
128 winterCGRequestToRequestData ,
139 withIsolationScope ,
1410} from '@sentry/core' ;
1511import { flushSafelyWithTimeout , waitUntil } from '../common/utils/responseEnd' ;
1612import { isPathnameUnderSentryTunnelRoute } from '../common/utils/tunnelPathnameMatch' ;
1713import type { EdgeRouteHandler } from '../edge/types' ;
18- import { SENTRY_KIND } from '@sentry/conventions/attributes' ;
1914
2015/**
21- * Wraps Next.js middleware with Sentry error and performance instrumentation.
16+ * Wraps Next.js middleware with Sentry error instrumentation.
17+ *
18+ * The middleware transaction itself is created by Next.js' native OpenTelemetry instrumentation
19+ * (the `Middleware.execute` span, normalized by `enhanceMiddlewareRootSpan`), so this wrapper no
20+ * longer starts its own span. It only forks an isolation scope, captures errors, and flushes.
2221 *
2322 * @param middleware The middleware handler.
2423 * @returns a wrapped middleware handler.
@@ -33,6 +32,7 @@ export function wrapMiddlewareWithSentry<H extends EdgeRouteHandler>(
3332 ? ( globalThis as Record < string , unknown > ) . _sentryRewritesTunnelPath
3433 : undefined ;
3534
35+ // TODO: This can never work with Turbopack, need to remove it for consistency between builds.
3636 if ( tunnelRoute && typeof tunnelRoute === 'string' ) {
3737 const req : unknown = args [ 0 ] ;
3838 // Check if the current request matches the tunnel route
@@ -53,66 +53,43 @@ export function wrapMiddlewareWithSentry<H extends EdgeRouteHandler>(
5353 }
5454 }
5555 }
56+
5657 // TODO: We still should add central isolation scope creation for when our build-time instrumentation does not work anymore with turbopack.
5758 return withIsolationScope ( isolationScope => {
5859 const req : unknown = args [ 0 ] ;
5960 const currentScope = getCurrentScope ( ) ;
6061
61- let spanName : string ;
62- let spanSource : TransactionSource ;
63-
6462 if ( req instanceof Request ) {
6563 isolationScope . setSDKProcessingMetadata ( {
6664 normalizedRequest : winterCGRequestToRequestData ( req ) ,
6765 } ) ;
68- spanName = `middleware ${ req . method } ` ;
69- spanSource = 'url' ;
66+ currentScope . setTransactionName ( `middleware ${ req . method } ` ) ;
7067 } else {
71- spanName = 'middleware' ;
72- spanSource = 'component' ;
68+ currentScope . setTransactionName ( 'middleware' ) ;
7369 }
7470
75- currentScope . setTransactionName ( spanName ) ;
76-
7771 const activeSpan = getActiveSpan ( ) ;
78-
7972 if ( activeSpan ) {
80- // If there is an active span, it likely means that the automatic Next.js OTEL instrumentation worked and we can
81- // rely on that for parameterization.
82- spanName = 'middleware' ;
83- spanSource = 'component' ;
84-
73+ // If there is an active span, the native Next.js OTEL instrumentation created the middleware root span.
74+ // Bind our forked scopes to it so the transaction picks up the isolation scope instead of the global one.
8575 const rootSpan = getRootSpan ( activeSpan ) ;
8676 if ( rootSpan ) {
8777 setCapturedScopesOnSpan ( rootSpan , currentScope , isolationScope ) ;
8878 }
8979 }
9080
91- return startSpan (
92- {
93- name : spanName ,
94- op : 'http.server.middleware' ,
95- attributes : {
96- [ SENTRY_KIND ] : 'server ' ,
97- [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : spanSource ,
98- [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.function.nextjs.wrap_middleware' ,
99- } ,
81+ return handleCallbackErrors (
82+ ( ) => wrappingTarget . apply ( thisArg , args ) ,
83+ error => {
84+ captureException ( error , {
85+ mechanism : {
86+ type : 'auto.function.nextjs.wrap_middleware ' ,
87+ handled : false ,
88+ } ,
89+ } ) ;
10090 } ,
10191 ( ) => {
102- return handleCallbackErrors (
103- ( ) => wrappingTarget . apply ( thisArg , args ) ,
104- error => {
105- captureException ( error , {
106- mechanism : {
107- type : 'auto.function.nextjs.wrap_middleware' ,
108- handled : false ,
109- } ,
110- } ) ;
111- } ,
112- ( ) => {
113- waitUntil ( flushSafelyWithTimeout ( ) ) ;
114- } ,
115- ) ;
92+ waitUntil ( flushSafelyWithTimeout ( ) ) ;
11693 } ,
11794 ) ;
11895 } ) ;
0 commit comments