diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/server-components.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/server-components.test.ts index 4f564f2f462d..498c9b969ed9 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/server-components.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/server-components.test.ts @@ -25,6 +25,7 @@ test('Sends a transaction for a request to app router', async ({ page }) => { 'http.status_code': 200, 'http.target': '/server-component/parameter/1337/42', 'otel.kind': 'SERVER', + 'next.route': '/server-component/parameter/[...parameters]', }), op: 'http.server', origin: 'auto', diff --git a/packages/nextjs/src/server/index.ts b/packages/nextjs/src/server/index.ts index e4e437ebd691..a6594e7fae1e 100644 --- a/packages/nextjs/src/server/index.ts +++ b/packages/nextjs/src/server/index.ts @@ -176,6 +176,8 @@ export function init(options: NodeOptions): NodeClient | undefined { const route = spanAttributes['next.route'].replace(/\/route$/, ''); rootSpan.updateName(route); rootSpan.setAttribute(ATTR_HTTP_ROUTE, route); + // Preserving the original attribute despite internally not depending on it + rootSpan.setAttribute('next.route', route); } } @@ -322,11 +324,14 @@ export function init(options: NodeOptions): NodeClient | undefined { const method = event.contexts.trace.data[SEMATTRS_HTTP_METHOD]; // eslint-disable-next-line deprecation/deprecation const target = event.contexts?.trace?.data?.[SEMATTRS_HTTP_TARGET]; - const route = event.contexts.trace.data[ATTR_HTTP_ROUTE]; + const route = event.contexts.trace.data[ATTR_HTTP_ROUTE] || event.contexts.trace.data['next.route']; if (typeof method === 'string' && typeof route === 'string') { - event.transaction = `${method} ${route.replace(/\/route$/, '')}`; + const cleanRoute = route.replace(/\/route$/, ''); + event.transaction = `${method} ${cleanRoute}`; event.contexts.trace.data[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] = 'route'; + // Preserve next.route in case it did not get hoisted + event.contexts.trace.data['next.route'] = cleanRoute; } // backfill transaction name for pages that would otherwise contain unparameterized routes