diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 23facb23c4902..b376393bea0eb 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -877,6 +877,8 @@ async function renderToHTMLOrFlightImpl( res, } + getTracer().getRootSpanAttributes()?.set('next.route', pagePath) + if (isRSCRequest && !isStaticGeneration) { return generateFlight(ctx) } @@ -900,8 +902,6 @@ async function renderToHTMLOrFlightImpl( const { ServerInsertedHTMLProvider, renderServerInsertedHTML } = createServerInsertedHTML() - getTracer().getRootSpanAttributes()?.set('next.route', pagePath) - const renderToStream = getTracer().wrap( AppRenderSpan.getBodyResult, { diff --git a/test/e2e/opentelemetry/instrumentation/__snapshots__/opentelemetry.test.ts.snap b/test/e2e/opentelemetry/instrumentation/__snapshots__/opentelemetry.test.ts.snap new file mode 100644 index 0000000000000..e7d58ff4eb115 --- /dev/null +++ b/test/e2e/opentelemetry/instrumentation/__snapshots__/opentelemetry.test.ts.snap @@ -0,0 +1,741 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`opentelemetry incoming context propagation app router should handle client-side navigation 1`] = ` +[ + { + "attributes": { + "next.route": "/app/[param]/loading/page1", + "next.span_name": "resolve page components", + "next.span_type": "NextNodeServer.findPageComponents", + }, + "duration": 170.875, + "events": [], + "id": "09c96f86f462995f", + "kind": 0, + "links": [], + "name": "resolve page components", + "parentId": "b5d89814ae8a3785", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828323740000, + "traceId": "5d5a2e8cb93bce9598d008f9527acce7", + }, + { + "attributes": { + "next.segment": "[param]", + "next.span_name": "resolve segment modules", + "next.span_type": "NextNodeServer.getLayoutOrPageModule", + }, + "duration": 21.583, + "events": [], + "id": "474afbf4c184decb", + "kind": 0, + "links": [], + "name": "resolve segment modules", + "parentId": "5e4ad2d3e35c5ca6", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828323742000, + "traceId": "5d5a2e8cb93bce9598d008f9527acce7", + }, + { + "attributes": { + "next.span_name": "build component tree", + "next.span_type": "NextNodeServer.createComponentTree", + }, + "duration": 531.708, + "events": [], + "id": "5e4ad2d3e35c5ca6", + "kind": 0, + "links": [], + "name": "build component tree", + "parentId": "d9f18e48ee445b87", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828323742000, + "traceId": "5d5a2e8cb93bce9598d008f9527acce7", + }, + { + "attributes": { + "next.segment": "__PAGE__", + "next.span_name": "resolve segment modules", + "next.span_type": "NextNodeServer.getLayoutOrPageModule", + }, + "duration": 20.75, + "events": [], + "id": "1f3de733e4e72874", + "kind": 0, + "links": [], + "name": "resolve segment modules", + "parentId": "5e4ad2d3e35c5ca6", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828323742000, + "traceId": "5d5a2e8cb93bce9598d008f9527acce7", + }, + { + "attributes": { + "next.page": "/app/[param]/layout", + "next.span_name": "generateMetadata /app/[param]/layout", + "next.span_type": "ResolveMetadata.generateMetadata", + }, + "duration": 18.167, + "events": [], + "id": "947a0cdf9d432ddb", + "kind": 0, + "links": [], + "name": "generateMetadata /app/[param]/layout", + "parentId": "d9f18e48ee445b87", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828323745000, + "traceId": "5d5a2e8cb93bce9598d008f9527acce7", + }, + { + "attributes": { + "next.span_name": "start response", + "next.span_type": "NextNodeServer.startResponse", + }, + "duration": 9.5, + "events": [], + "id": "4729a09c9abaf881", + "kind": 0, + "links": [], + "name": "start response", + "parentId": "d9f18e48ee445b87", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828323747000, + "traceId": "5d5a2e8cb93bce9598d008f9527acce7", + }, + { + "attributes": { + "next.route": "/app/[param]/loading/page1", + "next.span_name": "render route (app) /app/[param]/loading/page1", + "next.span_type": "AppRender.getBodyResult", + }, + "duration": 4530.667, + "events": [], + "id": "d9f18e48ee445b87", + "kind": 0, + "links": [], + "name": "render route (app) /app/[param]/loading/page1", + "parentId": "b5d89814ae8a3785", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828323741000, + "traceId": "5d5a2e8cb93bce9598d008f9527acce7", + }, + { + "attributes": { + "next.clientComponentLoadCount": 5, + }, + "duration": 9.958, + "events": [], + "id": "9a80488e523592a4", + "kind": 0, + "links": [], + "name": "NextNodeServer.clientComponentLoading", + "parentId": "d9f18e48ee445b87", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828323744233, + "traceId": "5d5a2e8cb93bce9598d008f9527acce7", + }, + { + "attributes": { + "http.method": "GET", + "http.route": "/app/[param]/loading/page1", + "http.status_code": 200, + "http.target": "/app/foo/loading/page1", + "next.route": "/app/[param]/loading/page1", + "next.rsc": false, + "next.span_name": "GET /app/[param]/loading/page1", + "next.span_type": "BaseServer.handleRequest", + }, + "duration": 512386.25, + "events": [], + "id": "b5d89814ae8a3785", + "kind": 1, + "links": [], + "name": "GET /app/[param]/loading/page1", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828323740000, + "traceId": "5d5a2e8cb93bce9598d008f9527acce7", + }, + { + "attributes": { + "next.route": "/app/[param]/loading/page2", + "next.span_name": "resolve page components", + "next.span_type": "NextNodeServer.findPageComponents", + }, + "duration": 102.875, + "events": [], + "id": "d3dbb304cf8b1d20", + "kind": 0, + "links": [], + "name": "resolve page components", + "parentId": "2be589c6b654639f", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828324275000, + "traceId": "b108b059df9687b1ddc7f7668c3c1d1c", + }, + { + "attributes": { + "next.span_name": "start response", + "next.span_type": "NextNodeServer.startResponse", + }, + "duration": 11.209, + "events": [], + "id": "9b71a10e381ba2d9", + "kind": 0, + "links": [], + "name": "start response", + "parentId": "2be589c6b654639f", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828324277000, + "traceId": "b108b059df9687b1ddc7f7668c3c1d1c", + }, + { + "attributes": { + "http.method": "GET", + "http.route": "/app/[param]/loading/page2", + "http.status_code": 200, + "http.target": "/app/foo/loading/page2?_rsc=tjhyf", + "next.route": "/app/[param]/loading/page2", + "next.rsc": true, + "next.span_name": "RSC GET /app/[param]/loading/page2", + "next.span_type": "BaseServer.handleRequest", + }, + "duration": 3384.292, + "events": [], + "id": "2be589c6b654639f", + "kind": 1, + "links": [], + "name": "RSC GET /app/[param]/loading/page2", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828324274000, + "traceId": "b108b059df9687b1ddc7f7668c3c1d1c", + }, + { + "attributes": { + "next.route": "/app/[param]/loading/page2", + "next.span_name": "resolve page components", + "next.span_type": "NextNodeServer.findPageComponents", + }, + "duration": 120.792, + "events": [], + "id": "2047a97fc18855ec", + "kind": 0, + "links": [], + "name": "resolve page components", + "parentId": "e38488814f571329", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828324340000, + "traceId": "0d6c1543230df4c288312d4c179d2d79", + }, + { + "attributes": { + "next.span_name": "build component tree", + "next.span_type": "NextNodeServer.createComponentTree", + }, + "duration": 560.917, + "events": [], + "id": "4cee7b5a66761fd6", + "kind": 0, + "links": [], + "name": "build component tree", + "parentId": "e38488814f571329", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828324341000, + "traceId": "0d6c1543230df4c288312d4c179d2d79", + }, + { + "attributes": { + "next.span_name": "start response", + "next.span_type": "NextNodeServer.startResponse", + }, + "duration": 12.667, + "events": [], + "id": "e0656af2298f1a78", + "kind": 0, + "links": [], + "name": "start response", + "parentId": "e38488814f571329", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828324343000, + "traceId": "0d6c1543230df4c288312d4c179d2d79", + }, + { + "attributes": { + "next.page": "/app/[param]/layout", + "next.span_name": "generateMetadata /app/[param]/layout", + "next.span_type": "ResolveMetadata.generateMetadata", + }, + "duration": 22.833, + "events": [], + "id": "bbcc32e4994f8a16", + "kind": 0, + "links": [], + "name": "generateMetadata /app/[param]/layout", + "parentId": "e38488814f571329", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828324344000, + "traceId": "0d6c1543230df4c288312d4c179d2d79", + }, + { + "attributes": { + "next.segment": "__PAGE__", + "next.span_name": "resolve segment modules", + "next.span_type": "NextNodeServer.getLayoutOrPageModule", + }, + "duration": 82, + "events": [], + "id": "6cfa448cf5fdd5fe", + "kind": 0, + "links": [], + "name": "resolve segment modules", + "parentId": "4cee7b5a66761fd6", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828324341000, + "traceId": "0d6c1543230df4c288312d4c179d2d79", + }, + { + "attributes": { + "http.method": "GET", + "http.route": "/app/[param]/loading/page2", + "http.status_code": 200, + "http.target": "/app/foo/loading/page2?_rsc=11iod", + "next.route": "/app/[param]/loading/page2", + "next.rsc": true, + "next.span_name": "RSC GET /app/[param]/loading/page2", + "next.span_type": "BaseServer.handleRequest", + }, + "duration": 507666.583, + "events": [], + "id": "e38488814f571329", + "kind": 1, + "links": [], + "name": "RSC GET /app/[param]/loading/page2", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828324340000, + "traceId": "0d6c1543230df4c288312d4c179d2d79", + }, +] +`; + +exports[`opentelemetry root context app router should handle client-side navigation 1`] = ` +[ + { + "attributes": { + "next.route": "/app/[param]/loading/page1", + "next.span_name": "resolve page components", + "next.span_type": "NextNodeServer.findPageComponents", + }, + "duration": 87.5, + "events": [], + "id": "98978cccb0a87e95", + "kind": 0, + "links": [], + "name": "resolve page components", + "parentId": "a8ef684cf17adeb9", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828309586000, + "traceId": "dfab070c61d3909e9c61144462be133e", + }, + { + "attributes": { + "next.segment": "[param]", + "next.span_name": "resolve segment modules", + "next.span_type": "NextNodeServer.getLayoutOrPageModule", + }, + "duration": 34.084, + "events": [], + "id": "34bb44ac38b6f0a5", + "kind": 0, + "links": [], + "name": "resolve segment modules", + "parentId": "3c37465e5e82510d", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828309589000, + "traceId": "dfab070c61d3909e9c61144462be133e", + }, + { + "attributes": { + "next.span_name": "build component tree", + "next.span_type": "NextNodeServer.createComponentTree", + }, + "duration": 1412.541, + "events": [], + "id": "3c37465e5e82510d", + "kind": 0, + "links": [], + "name": "build component tree", + "parentId": "f74e9bbee479cd47", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828309588000, + "traceId": "dfab070c61d3909e9c61144462be133e", + }, + { + "attributes": { + "next.route": "/app/[param]/loading/page1", + "next.span_name": "render route (app) /app/[param]/loading/page1", + "next.span_type": "AppRender.getBodyResult", + }, + "duration": 7391.792, + "events": [], + "id": "f74e9bbee479cd47", + "kind": 0, + "links": [], + "name": "render route (app) /app/[param]/loading/page1", + "parentId": "a8ef684cf17adeb9", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828309587000, + "traceId": "dfab070c61d3909e9c61144462be133e", + }, + { + "attributes": { + "next.segment": "__PAGE__", + "next.span_name": "resolve segment modules", + "next.span_type": "NextNodeServer.getLayoutOrPageModule", + }, + "duration": 25.709, + "events": [], + "id": "6b95decf0bbaf8b1", + "kind": 0, + "links": [], + "name": "resolve segment modules", + "parentId": "3c37465e5e82510d", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828309589000, + "traceId": "dfab070c61d3909e9c61144462be133e", + }, + { + "attributes": { + "next.page": "/app/[param]/layout", + "next.span_name": "generateMetadata /app/[param]/layout", + "next.span_type": "ResolveMetadata.generateMetadata", + }, + "duration": 19.5, + "events": [], + "id": "7d04403a7cb8d014", + "kind": 0, + "links": [], + "name": "generateMetadata /app/[param]/layout", + "parentId": "f74e9bbee479cd47", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828309592000, + "traceId": "dfab070c61d3909e9c61144462be133e", + }, + { + "attributes": { + "next.span_name": "start response", + "next.span_type": "NextNodeServer.startResponse", + }, + "duration": 10.208, + "events": [], + "id": "57c7f4ac74cb7cbf", + "kind": 0, + "links": [], + "name": "start response", + "parentId": "f74e9bbee479cd47", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828309596000, + "traceId": "dfab070c61d3909e9c61144462be133e", + }, + { + "attributes": { + "next.clientComponentLoadCount": 5, + }, + "duration": 14.25, + "events": [], + "id": "c79bbdc913a7fd41", + "kind": 0, + "links": [], + "name": "NextNodeServer.clientComponentLoading", + "parentId": "f74e9bbee479cd47", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828309591483.8, + "traceId": "dfab070c61d3909e9c61144462be133e", + }, + { + "attributes": { + "http.method": "GET", + "http.route": "/app/[param]/loading/page1", + "http.status_code": 200, + "http.target": "/app/foo/loading/page1", + "next.route": "/app/[param]/loading/page1", + "next.rsc": false, + "next.span_name": "GET /app/[param]/loading/page1", + "next.span_type": "BaseServer.handleRequest", + }, + "duration": 521727.708, + "events": [], + "id": "a8ef684cf17adeb9", + "kind": 1, + "links": [], + "name": "GET /app/[param]/loading/page1", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828309585000, + "traceId": "dfab070c61d3909e9c61144462be133e", + }, + { + "attributes": { + "next.route": "/app/[param]/loading/page2", + "next.span_name": "resolve page components", + "next.span_type": "NextNodeServer.findPageComponents", + }, + "duration": 156.542, + "events": [], + "id": "0c79afdbfbb1e0f6", + "kind": 0, + "links": [], + "name": "resolve page components", + "parentId": "f95c305a64c1d71c", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828310141000, + "traceId": "c8ee82aa15bab3736d7e0f608c92bbe8", + }, + { + "attributes": { + "next.span_name": "start response", + "next.span_type": "NextNodeServer.startResponse", + }, + "duration": 18.667, + "events": [], + "id": "f4a9aa06018c421d", + "kind": 0, + "links": [], + "name": "start response", + "parentId": "f95c305a64c1d71c", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828310146000, + "traceId": "c8ee82aa15bab3736d7e0f608c92bbe8", + }, + { + "attributes": { + "http.method": "GET", + "http.route": "/app/[param]/loading/page2", + "http.status_code": 200, + "http.target": "/app/foo/loading/page2?_rsc=tjhyf", + "next.route": "/app/[param]/loading/page2", + "next.rsc": true, + "next.span_name": "RSC GET /app/[param]/loading/page2", + "next.span_type": "BaseServer.handleRequest", + }, + "duration": 7208.166, + "events": [], + "id": "f95c305a64c1d71c", + "kind": 1, + "links": [], + "name": "RSC GET /app/[param]/loading/page2", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828310140000, + "traceId": "c8ee82aa15bab3736d7e0f608c92bbe8", + }, + { + "attributes": { + "next.route": "/app/[param]/loading/page2", + "next.span_name": "resolve page components", + "next.span_type": "NextNodeServer.findPageComponents", + }, + "duration": 95.5, + "events": [], + "id": "f53658b0f59fa556", + "kind": 0, + "links": [], + "name": "resolve page components", + "parentId": "6e8569377f2a6820", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828310207000, + "traceId": "00a2fc222e9b84a206b4e051abb37507", + }, + { + "attributes": { + "next.span_name": "build component tree", + "next.span_type": "NextNodeServer.createComponentTree", + }, + "duration": 433.791, + "events": [], + "id": "033016075b37475b", + "kind": 0, + "links": [], + "name": "build component tree", + "parentId": "6e8569377f2a6820", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828310209000, + "traceId": "00a2fc222e9b84a206b4e051abb37507", + }, + { + "attributes": { + "next.span_name": "start response", + "next.span_type": "NextNodeServer.startResponse", + }, + "duration": 9.291, + "events": [], + "id": "2f39a1cc4c856ace", + "kind": 0, + "links": [], + "name": "start response", + "parentId": "6e8569377f2a6820", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828310210000, + "traceId": "00a2fc222e9b84a206b4e051abb37507", + }, + { + "attributes": { + "next.page": "/app/[param]/layout", + "next.span_name": "generateMetadata /app/[param]/layout", + "next.span_type": "ResolveMetadata.generateMetadata", + }, + "duration": 18.959, + "events": [], + "id": "1bc21cf0c9c5a53d", + "kind": 0, + "links": [], + "name": "generateMetadata /app/[param]/layout", + "parentId": "6e8569377f2a6820", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828310211000, + "traceId": "00a2fc222e9b84a206b4e051abb37507", + }, + { + "attributes": { + "next.segment": "__PAGE__", + "next.span_name": "resolve segment modules", + "next.span_type": "NextNodeServer.getLayoutOrPageModule", + }, + "duration": 44.709, + "events": [], + "id": "cdcaa32b04cba524", + "kind": 0, + "links": [], + "name": "resolve segment modules", + "parentId": "033016075b37475b", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828310209000, + "traceId": "00a2fc222e9b84a206b4e051abb37507", + }, + { + "attributes": { + "http.method": "GET", + "http.route": "/app/[param]/loading/page2", + "http.status_code": 200, + "http.target": "/app/foo/loading/page2?_rsc=11iod", + "next.route": "/app/[param]/loading/page2", + "next.rsc": true, + "next.span_name": "RSC GET /app/[param]/loading/page2", + "next.span_type": "BaseServer.handleRequest", + }, + "duration": 509500.541, + "events": [], + "id": "6e8569377f2a6820", + "kind": 1, + "links": [], + "name": "RSC GET /app/[param]/loading/page2", + "runtime": "nodejs", + "status": { + "code": 0, + }, + "timestamp": 1715828310207000, + "traceId": "00a2fc222e9b84a206b4e051abb37507", + }, +] +`; diff --git a/test/e2e/opentelemetry/instrumentation/app/app/[param]/loading/page1/page.tsx b/test/e2e/opentelemetry/instrumentation/app/app/[param]/loading/page1/page.tsx index 2fbdff3f713ba..14c64e9b20a6d 100644 --- a/test/e2e/opentelemetry/instrumentation/app/app/[param]/loading/page1/page.tsx +++ b/test/e2e/opentelemetry/instrumentation/app/app/[param]/loading/page1/page.tsx @@ -3,12 +3,16 @@ import Link from 'next/link' // We want to trace this fetch in runtime export const dynamic = 'force-dynamic' -export default async function Page() { - await new Promise((resolve) => setTimeout(resolve, 5000)) +export default async function Page({ + params: { param }, +}: { + params: { param: string } +}) { + await new Promise((resolve) => setTimeout(resolve, 500)) return ( <> -
app/loading/page1
- Page2 +app/{param}/loading/page1
+ Page2 > ) } diff --git a/test/e2e/opentelemetry/instrumentation/app/app/[param]/loading/page2/page.tsx b/test/e2e/opentelemetry/instrumentation/app/app/[param]/loading/page2/page.tsx index ee2b37fe5a6ac..245158a45a1ab 100644 --- a/test/e2e/opentelemetry/instrumentation/app/app/[param]/loading/page2/page.tsx +++ b/test/e2e/opentelemetry/instrumentation/app/app/[param]/loading/page2/page.tsx @@ -3,12 +3,16 @@ import Link from 'next/link' // We want to trace this fetch in runtime export const dynamic = 'force-dynamic' -export default async function Page() { - await new Promise((resolve) => setTimeout(resolve, 5000)) +export default async function Page({ + params: { param }, +}: { + params: { param: string } +}) { + await new Promise((resolve) => setTimeout(resolve, 500)) return ( <> -app/loading/page2
- Page1 +app/{param}/loading/page2
+ Page1 > ) } diff --git a/test/e2e/opentelemetry/instrumentation/opentelemetry.test.ts b/test/e2e/opentelemetry/instrumentation/opentelemetry.test.ts index cbb0b3a06bef4..bb98cc8e72da7 100644 --- a/test/e2e/opentelemetry/instrumentation/opentelemetry.test.ts +++ b/test/e2e/opentelemetry/instrumentation/opentelemetry.test.ts @@ -1,5 +1,6 @@ import { nextTestSetup } from 'e2e-utils' import { check } from 'next-test-utils' +import webdriver from 'next-webdriver' import { SavedSpan } from './constants' import { type Collector, connectCollector } from './collector' @@ -524,6 +525,17 @@ describe('opentelemetry', () => { }, ]) }) + + it('should handle client-side navigation', async () => { + const browser = await webdriver(next.url, `/app/foo/loading/page1`, { + waitHydration: true, + }) + + await browser.waitForElementByCss('#page1') + await browser.elementByCss('a').click().waitForElementByCss('#page2') + + expect(getCollector().getSpans()).toMatchSnapshot() + }) }) describe('pages', () => {