diff --git a/plugins/node/opentelemetry-instrumentation-koa/src/utils.ts b/plugins/node/opentelemetry-instrumentation-koa/src/utils.ts index 2061392e3e..e1d92d8abe 100644 --- a/plugins/node/opentelemetry-instrumentation-koa/src/utils.ts +++ b/plugins/node/opentelemetry-instrumentation-koa/src/utils.ts @@ -39,7 +39,7 @@ export const getMiddlewareMetadata = ( [AttributeNames.KOA_TYPE]: KoaLayerType.ROUTER, [SemanticAttributes.HTTP_ROUTE]: layerPath, }, - name: `router - ${layerPath}`, + name: context._matchedRouteName || `router - ${layerPath}`, }; } else { return { diff --git a/plugins/node/opentelemetry-instrumentation-koa/test/koa.test.ts b/plugins/node/opentelemetry-instrumentation-koa/test/koa.test.ts index 8aab685309..063985343a 100644 --- a/plugins/node/opentelemetry-instrumentation-koa/test/koa.test.ts +++ b/plugins/node/opentelemetry-instrumentation-koa/test/koa.test.ts @@ -171,6 +171,56 @@ describe('Koa Instrumentation', () => { ); }); + it('should create a named child span for middlewares', async () => { + const rootSpan = tracer.startSpan('rootSpan'); + const rpcMetadata = { type: RPCType.HTTP, span: rootSpan }; + app.use((ctx, next) => + context.with( + setRPCMetadata( + trace.setSpan(context.active(), rootSpan), + rpcMetadata + ), + next + ) + ); + + const router = new KoaRouter(); + router.get('retrievePost', '/post/:id', ctx => { + ctx.body = `Post id: ${ctx.params.id}`; + }); + + app.use(router.routes()); + + await context.with( + trace.setSpan(context.active(), rootSpan), + async () => { + await httpRequest.get(`http://localhost:${port}/post/0`); + rootSpan.end(); + + assert.deepStrictEqual(memoryExporter.getFinishedSpans().length, 2); + const requestHandlerSpan = memoryExporter + .getFinishedSpans() + .find(span => span.name === 'retrievePost'); + assert.notStrictEqual(requestHandlerSpan, undefined); + + assert.strictEqual( + requestHandlerSpan?.attributes[AttributeNames.KOA_TYPE], + KoaLayerType.ROUTER + ); + + assert.strictEqual( + requestHandlerSpan?.attributes[SemanticAttributes.HTTP_ROUTE], + '/post/:id' + ); + + const exportedRootSpan = memoryExporter + .getFinishedSpans() + .find(span => span.name === 'GET /post/:id'); + assert.notStrictEqual(exportedRootSpan, undefined); + } + ); + }); + it('should correctly instrument nested routers', async () => { const rootSpan = tracer.startSpan('rootSpan'); const rpcMetadata = { type: RPCType.HTTP, span: rootSpan };