@@ -242,6 +242,22 @@ export function init(options: NodeOptions): NodeClient | undefined {
242242 return null ;
243243 }
244244
245+ // Next.js 13 sometimes names the root transactions like this containing useless tracing.
246+ if ( event . transaction === 'NextServer.getRequestHandler' ) {
247+ return null ;
248+ }
249+
250+ // Next.js 13 is not correctly picking up tracing data for trace propagation so we use a back-fill strategy
251+ if ( typeof event . contexts ?. trace ?. data ?. [ TRANSACTION_ATTR_SENTRY_TRACE_BACKFILL ] === 'string' ) {
252+ const traceparentData = extractTraceparentData (
253+ event . contexts . trace . data [ TRANSACTION_ATTR_SENTRY_TRACE_BACKFILL ] ,
254+ ) ;
255+
256+ if ( traceparentData ?. parentSampled === false ) {
257+ return null ;
258+ }
259+ }
260+
245261 return event ;
246262 } else {
247263 return event ;
@@ -286,78 +302,62 @@ export function init(options: NodeOptions): NodeClient | undefined {
286302 ) ,
287303 ) ;
288304
289- // TODO: move this into pre-processing hook
290- getGlobalScope ( ) . addEventProcessor (
291- Object . assign (
292- ( event => {
293- // Enhance route handler transactions
294- if (
295- event . type === 'transaction' &&
296- event . contexts ?. trace ?. data ?. [ 'next.span_type' ] === 'BaseServer.handleRequest'
297- ) {
298- event . contexts . trace . data = event . contexts . trace . data || { } ;
299- event . contexts . trace . data [ SEMANTIC_ATTRIBUTE_SENTRY_OP ] = 'http.server' ;
300- event . contexts . trace . op = 'http.server' ;
301-
302- if ( event . transaction ) {
303- event . transaction = stripUrlQueryAndFragment ( event . transaction ) ;
304- }
305-
306- // eslint-disable-next-line deprecation/deprecation
307- const method = event . contexts . trace . data [ SEMATTRS_HTTP_METHOD ] ;
308- // eslint-disable-next-line deprecation/deprecation
309- const target = event . contexts ?. trace ?. data ?. [ SEMATTRS_HTTP_TARGET ] ;
310- const route = event . contexts . trace . data [ ATTR_HTTP_ROUTE ] ;
311-
312- if ( typeof method === 'string' && typeof route === 'string' ) {
313- event . transaction = `${ method } ${ route . replace ( / \/ r o u t e $ / , '' ) } ` ;
314- event . contexts . trace . data [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] = 'route' ;
315- }
305+ // Use the preprocessEvent hook instead of an event processor, so that the users event processors receive the most
306+ // up-to-date value, but also so that the logic that detects changes to the transaction names to set the source to
307+ // "custom", doesn't trigger.
308+ client ?. on ( 'preprocessEvent' , event => {
309+ // Enhance route handler transactions
310+ if (
311+ event . type === 'transaction' &&
312+ event . contexts ?. trace ?. data ?. [ 'next.span_type' ] === 'BaseServer.handleRequest'
313+ ) {
314+ event . contexts . trace . data = event . contexts . trace . data || { } ;
315+ event . contexts . trace . data [ SEMANTIC_ATTRIBUTE_SENTRY_OP ] = 'http.server' ;
316+ event . contexts . trace . op = 'http.server' ;
316317
317- // backfill transaction name for pages that would otherwise contain unparameterized routes
318- if ( event . contexts . trace . data [ 'sentry.route_backfill' ] && event . transaction !== 'GET /_app' ) {
319- event . transaction = `${ method } ${ event . contexts . trace . data [ TRANSACTION_ATTR_SENTRY_ROUTE_BACKFILL ] } ` ;
320- }
318+ if ( event . transaction ) {
319+ event . transaction = stripUrlQueryAndFragment ( event . transaction ) ;
320+ }
321321
322- // Next.js overrides transaction names for page loads that throw an error
323- // but we want to keep the original target name
324- if ( event . transaction === 'GET /_error' && target ) {
325- event . transaction = `${ method ? `${ method } ` : '' } ${ target } ` ;
326- }
327- }
322+ // eslint-disable-next-line deprecation/deprecation
323+ const method = event . contexts . trace . data [ SEMATTRS_HTTP_METHOD ] ;
324+ // eslint-disable-next-line deprecation/deprecation
325+ const target = event . contexts ?. trace ?. data ?. [ SEMATTRS_HTTP_TARGET ] ;
326+ const route = event . contexts . trace . data [ ATTR_HTTP_ROUTE ] ;
328327
329- // Next.js 13 is not correctly picking up tracing data for trace propagation so we use a back-fill strategy
330- if (
331- event . type === 'transaction' &&
332- typeof event . contexts ?. trace ?. data ?. [ TRANSACTION_ATTR_SENTRY_TRACE_BACKFILL ] === 'string'
333- ) {
334- const traceparentData = extractTraceparentData (
335- event . contexts . trace . data [ TRANSACTION_ATTR_SENTRY_TRACE_BACKFILL ] ,
336- ) ;
328+ if ( typeof method === 'string' && typeof route === 'string' ) {
329+ event . transaction = `${ method } ${ route . replace ( / \/ r o u t e $ / , '' ) } ` ;
330+ event . contexts . trace . data [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] = 'route' ;
331+ }
337332
338- if ( traceparentData ?. parentSampled === false ) {
339- return null ;
340- }
333+ // backfill transaction name for pages that would otherwise contain unparameterized routes
334+ if ( event . contexts . trace . data [ 'sentry.route_backfill' ] && event . transaction !== 'GET /_app' ) {
335+ event . transaction = `${ method } ${ event . contexts . trace . data [ TRANSACTION_ATTR_SENTRY_ROUTE_BACKFILL ] } ` ;
336+ }
341337
342- if ( traceparentData ?. traceId ) {
343- event . contexts . trace . trace_id = traceparentData . traceId ;
344- }
338+ // Next.js overrides transaction names for page loads that throw an error
339+ // but we want to keep the original target name
340+ if ( event . transaction === 'GET /_error' && target ) {
341+ event . transaction = `${ method ? `${ method } ` : '' } ${ target } ` ;
342+ }
343+ }
345344
346- if ( traceparentData ?. parentSpanId ) {
347- event . contexts . trace . parent_span_id = traceparentData . parentSpanId ;
348- }
349- }
345+ // Next.js 13 is not correctly picking up tracing data for trace propagation so we use a back-fill strategy
346+ if (
347+ event . type === 'transaction' &&
348+ typeof event . contexts ?. trace ?. data ?. [ TRANSACTION_ATTR_SENTRY_TRACE_BACKFILL ] === 'string'
349+ ) {
350+ const traceparentData = extractTraceparentData ( event . contexts . trace . data [ TRANSACTION_ATTR_SENTRY_TRACE_BACKFILL ] ) ;
350351
351- // Next.js 13 sometimes names the root transactions like this containing useless tracing.
352- if ( event . type === 'transaction' && event . transaction === 'NextServer.getRequestHandler' ) {
353- return null ;
354- }
352+ if ( traceparentData ?. traceId ) {
353+ event . contexts . trace . trace_id = traceparentData . traceId ;
354+ }
355355
356- return event ;
357- } ) satisfies EventProcessor ,
358- { id : 'NextjsTransactionEnhancer' } ,
359- ) ,
360- ) ;
356+ if ( traceparentData ?. parentSpanId ) {
357+ event . contexts . trace . parent_span_id = traceparentData . parentSpanId ;
358+ }
359+ }
360+ } ) ;
361361
362362 if ( process . env . NODE_ENV === 'development' ) {
363363 getGlobalScope ( ) . addEventProcessor ( devErrorSymbolicationEventProcessor ) ;
0 commit comments