diff --git a/packages/next/src/server/next.ts b/packages/next/src/server/next.ts index c9e2a0af88f8..adf3cc25b4d1 100644 --- a/packages/next/src/server/next.ts +++ b/packages/next/src/server/next.ts @@ -149,10 +149,13 @@ export class NextServer implements NextWrapperServer { res: ServerResponse, parsedUrl?: NextUrlWithParsedQuery ) => { - return getTracer().trace(NextServerSpan.getRequestHandler, async () => { - const requestHandler = await this.getServerRequestHandler() - return requestHandler(req, res, parsedUrl) - }) + const tracer = getTracer() + return tracer.withPropagatedContext(req.headers, () => + tracer.trace(NextServerSpan.getRequestHandler, async () => { + const requestHandler = await this.getServerRequestHandler() + return requestHandler(req, res, parsedUrl) + }) + ) } } @@ -166,13 +169,13 @@ export class NextServer implements NextWrapperServer { res: ServerResponse, parsedUrl?: NextUrlWithParsedQuery ) => { - return getTracer().trace( - NextServerSpan.getRequestHandlerWithMetadata, - async () => { + const tracer = getTracer() + return tracer.withPropagatedContext(req.headers, () => + tracer.trace(NextServerSpan.getRequestHandlerWithMetadata, async () => { const server = await this.getServer() const handler = server.getRequestHandlerWithMetadata(meta) return handler(req, res, parsedUrl) - } + }) ) } } diff --git a/test/e2e/opentelemetry/instrumentation/opentelemetry.test.ts b/test/e2e/opentelemetry/instrumentation/opentelemetry.test.ts index fa07de919651..525eda27ea6b 100644 --- a/test/e2e/opentelemetry/instrumentation/opentelemetry.test.ts +++ b/test/e2e/opentelemetry/instrumentation/opentelemetry.test.ts @@ -1159,6 +1159,74 @@ describe('opentelemetry', () => { ) } }) +;(process.env.__NEXT_CACHE_COMPONENTS ? describe.skip : describe)( + 'opentelemetry NEXT_OTEL_VERBOSE=1', + () => { + const { next, skipped } = nextTestSetup({ + files: __dirname, + skipDeployment: true, + dependencies: require('./package.json').dependencies, + env: { + TEST_OTEL_COLLECTOR_PORT: String(COLLECTOR_PORT), + NEXT_TELEMETRY_DISABLED: '1', + NEXT_OTEL_VERBOSE: '1', + }, + }) + + if (skipped) { + return + } + + let collector: Collector | undefined + + beforeEach(async () => { + collector = await connectCollector({ port: COLLECTOR_PORT }) + }) + + afterEach(async () => { + await collector?.shutdown() + collector = undefined + }) + + // Regression for https://github.com/vercel/otel/issues/107. + it('all spans (including verbose) inherit traceId from incoming traceparent header', async () => { + const pathname = '/app/param/rsc-fetch' + await next.fetch(pathname, { + headers: { + traceparent: `00-${EXTERNAL.traceId}-${EXTERNAL.spanId}-01`, + }, + }) + + let spans: SavedSpan[] = [] + await retry(async () => { + const all = collector?.getSpans() ?? [] + const root = all.find( + (s) => + s.attributes?.['next.span_type'] === 'BaseServer.handleRequest' && + s.attributes?.['http.target'] === pathname + ) + expect(root).toBeDefined() + expect(root!.traceId).toBe(EXTERNAL.traceId) + + spans = all.filter((s) => s.traceId === root!.traceId) + expect(spans.length).toBeGreaterThan(1) + + const verbose = spans.find( + (s) => + s.attributes?.['next.span_type'] === 'NextServer.getRequestHandler' + ) + expect(verbose).toBeDefined() + expect(verbose!.traceId).toBe(EXTERNAL.traceId) + const parentSpanId = verbose!.parentId + expect(parentSpanId).toBe(EXTERNAL.spanId) + }) + + for (const span of spans) { + expect(span.traceId).toBe(EXTERNAL.traceId) + } + }) + } +) describe('opentelemetry with disabled fetch tracing', () => { const { next, skipped } = nextTestSetup({