@@ -242,6 +242,22 @@ export function init(options: NodeOptions): NodeClient | undefined {
242
242
return null ;
243
243
}
244
244
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
+
245
261
return event ;
246
262
} else {
247
263
return event ;
@@ -286,78 +302,62 @@ export function init(options: NodeOptions): NodeClient | undefined {
286
302
) ,
287
303
) ;
288
304
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' ;
316
317
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
+ }
321
321
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 ] ;
328
327
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
+ }
337
332
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
+ }
341
337
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
+ }
345
344
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 ] ) ;
350
351
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
+ }
355
355
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
+ } ) ;
361
361
362
362
if ( process . env . NODE_ENV === 'development' ) {
363
363
getGlobalScope ( ) . addEventProcessor ( devErrorSymbolicationEventProcessor ) ;
0 commit comments