Skip to content

Commit 4f3ccec

Browse files
committed
fix(express): Ensure 404 routes don't attach route attribute
1 parent cbd2ebe commit 4f3ccec

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

plugins/node/opentelemetry-instrumentation-express/src/instrumentation.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,10 @@ export class ExpressInstrumentation extends InstrumentationBase<ExpressInstrumen
194194
// remove duplicate slashes to normalize route
195195
.replace(/\/{2,}/g, '/');
196196

197+
const actualRoute = route.length > 0 ? route : undefined;
198+
197199
const attributes: Attributes = {
198-
[SEMATTRS_HTTP_ROUTE]: route.length > 0 ? route : '/',
200+
[SEMATTRS_HTTP_ROUTE]: actualRoute,
199201
};
200202
const metadata = getLayerMetadata(route, layer, layerPath);
201203
const type = metadata.attributes[
@@ -204,7 +206,7 @@ export class ExpressInstrumentation extends InstrumentationBase<ExpressInstrumen
204206

205207
const rpcMetadata = getRPCMetadata(context.active());
206208
if (rpcMetadata?.type === RPCType.HTTP) {
207-
rpcMetadata.route = route || '/';
209+
rpcMetadata.route = actualRoute;
208210
}
209211

210212
// verify against the config if the layer should be ignored

plugins/node/opentelemetry-instrumentation-express/test/express.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,46 @@ describe('ExpressInstrumentation', () => {
6767
server?.close();
6868
});
6969

70+
it('does not attach semantic route attribute for 404 page', async () => {
71+
const rootSpan = tracer.startSpan('rootSpan');
72+
const httpServer = await serverWithMiddleware(tracer, rootSpan, app => {
73+
app.use(express.json());
74+
});
75+
server = httpServer.server;
76+
port = httpServer.port;
77+
assert.strictEqual(memoryExporter.getFinishedSpans().length, 0);
78+
79+
await context.with(
80+
trace.setSpan(context.active(), rootSpan),
81+
async () => {
82+
try {
83+
await httpRequest.get(
84+
`http://localhost:${port}/non-existing-route`
85+
);
86+
} catch (error) {}
87+
rootSpan.end();
88+
89+
const spans = memoryExporter.getFinishedSpans();
90+
91+
// Should have middleware spans but no request handler span
92+
const middlewareSpans = spans.filter(span =>
93+
span.name.includes('middleware') ||
94+
span.name.includes('expressInit') ||
95+
span.name.includes('jsonParser')
96+
);
97+
98+
assert.ok(middlewareSpans.length > 0, 'Middleware spans should be created');
99+
100+
for (const span of spans) {
101+
assert.strictEqual(
102+
span.attributes[SEMATTRS_HTTP_ROUTE],
103+
undefined, // none of the spans have the HTTP route attribute
104+
`Span "${span.name}" should not have HTTP route attribute for non-existing route`
105+
);
106+
}
107+
}
108+
);
109+
});
70110
it('should create a child span for middlewares', async () => {
71111
const rootSpan = tracer.startSpan('rootSpan');
72112
const customMiddleware: express.RequestHandler = (req, res, next) => {

0 commit comments

Comments
 (0)