@@ -22,7 +22,11 @@ import {
2222import { getScopesFromContext } from '@sentry/opentelemetry' ;
2323import type { VercelEdgeOptions } from '@sentry/vercel-edge' ;
2424import { getDefaultIntegrations , init as vercelEdgeInit } from '@sentry/vercel-edge' ;
25- import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../common/span-attributes-with-logic-attached' ;
25+ import { ATTR_NEXT_SPAN_NAME , ATTR_NEXT_SPAN_TYPE } from '../common/nextSpanAttributes' ;
26+ import {
27+ ATTR_NEXT_PAGES_API_ROUTE_TYPE ,
28+ TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION ,
29+ } from '../common/span-attributes-with-logic-attached' ;
2630import { addHeadersAsAttributes } from '../common/utils/addHeadersAsAttributes' ;
2731import { dropMiddlewareTunnelRequests } from '../common/utils/dropMiddlewareTunnelRequests' ;
2832import { isBuild } from '../common/utils/isBuild' ;
@@ -82,12 +86,21 @@ export function init(options: VercelEdgeOptions = {}): void {
8286 dropMiddlewareTunnelRequests ( span , spanAttributes ) ;
8387
8488 // Mark all spans generated by Next.js as 'auto'
85- if ( spanAttributes ?. [ 'next.span_type' ] !== undefined ) {
89+ if ( spanAttributes ?. [ ATTR_NEXT_SPAN_TYPE ] !== undefined ) {
8690 span . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN , 'auto' ) ;
8791 }
8892
93+ // Backfill span attributes for api route pages because we removed it from the wrapper
94+ if (
95+ spanAttributes ?. [ ATTR_NEXT_SPAN_TYPE ] === 'Node.runHandler' &&
96+ String ( spanAttributes ?. [ 'next.span_name' ] ) . startsWith ( ATTR_NEXT_PAGES_API_ROUTE_TYPE )
97+ ) {
98+ span . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_OP , 'http.server' ) ;
99+ span . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_SOURCE , 'route' ) ;
100+ }
101+
89102 // Make sure middleware spans get the right op
90- if ( spanAttributes ?. [ 'next.span_type' ] === 'Middleware.execute' ) {
103+ if ( spanAttributes ?. [ ATTR_NEXT_SPAN_TYPE ] === 'Middleware.execute' ) {
91104 span . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_OP , 'http.server.middleware' ) ;
92105 span . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_SOURCE , 'url' ) ;
93106
@@ -119,8 +132,8 @@ export function init(options: VercelEdgeOptions = {}): void {
119132 // The otel auto inference will clobber the transaction name because the span has an http.target
120133 if (
121134 event . type === 'transaction' &&
122- event . contexts ?. trace ?. data ?. [ 'next.span_type' ] === 'Middleware.execute' &&
123- event . contexts ?. trace ?. data ?. [ 'next.span_name' ]
135+ event . contexts ?. trace ?. data ?. [ ATTR_NEXT_SPAN_TYPE ] === 'Middleware.execute' &&
136+ event . contexts ?. trace ?. data ?. [ ATTR_NEXT_SPAN_NAME ] !== undefined
124137 ) {
125138 if ( event . transaction ) {
126139 // Older nextjs versions pass the full url appended to the middleware name, which results in high cardinality transaction names.
@@ -139,6 +152,20 @@ export function init(options: VercelEdgeOptions = {}): void {
139152 }
140153 }
141154
155+ // Backfill the transaction name for api route pages because we removed it from the wrapper
156+ if (
157+ event . type === 'transaction' &&
158+ event . contexts ?. trace ?. data ?. [ ATTR_NEXT_SPAN_TYPE ] === 'Node.runHandler' &&
159+ String ( event . contexts . trace . data [ 'next.span_name' ] ) . startsWith ( ATTR_NEXT_PAGES_API_ROUTE_TYPE )
160+ ) {
161+ let path = String ( event . contexts . trace . data [ 'next.span_name' ] ) . replace ( ATTR_NEXT_PAGES_API_ROUTE_TYPE , '' ) . trim ( ) ;
162+ // Set transaction name on isolation scope to ensure parameterized routes are used
163+ // The HTTP server integration sets it on isolation scope, so we need to match that
164+ const method = event . request ?. method || 'GET' ;
165+ path = path ?? event . request ?. url ?? '/' ;
166+ event . transaction = `${ method } ${ path } ` ;
167+ }
168+
142169 setUrlProcessingMetadata ( event ) ;
143170 } ) ;
144171
0 commit comments