Skip to content

Commit 8d6662f

Browse files
feat(instrumentation-express): propagate context and measure full handler spans
1 parent 12ee8db commit 8d6662f

File tree

2 files changed

+13
-7
lines changed

2 files changed

+13
-7
lines changed

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ export class ExpressInstrumentation extends InstrumentationBase<ExpressInstrumen
215215
attributes: Object.assign(attributes, metadata.attributes),
216216
});
217217

218+
const parentContext = context.active();
219+
let currentContext = trace.setSpan(parentContext, span);
220+
218221
const { requestHook } = instrumentation.getConfig();
219222
if (requestHook) {
220223
safeExecuteInTheMiddle(
@@ -234,12 +237,15 @@ export class ExpressInstrumentation extends InstrumentationBase<ExpressInstrumen
234237
}
235238

236239
let spanHasEnded = false;
240+
// TODO: Fix router spans (getRouterPath does not work properly) to
241+
// have useful names before removing this branch
237242
if (
238-
metadata.attributes[AttributeNames.EXPRESS_TYPE] !==
239-
ExpressLayerType.MIDDLEWARE
243+
metadata.attributes[AttributeNames.EXPRESS_TYPE] ===
244+
ExpressLayerType.ROUTER
240245
) {
241246
span.end();
242247
spanHasEnded = true;
248+
currentContext = parentContext;
243249
}
244250
// listener for response.on('finish')
245251
const onResponseFinish = () => {
@@ -278,12 +284,12 @@ export class ExpressInstrumentation extends InstrumentationBase<ExpressInstrumen
278284
(req[_LAYERS_STORE_PROPERTY] as string[]).pop();
279285
}
280286
const callback = args[callbackIdx] as Function;
281-
return callback.apply(this, arguments);
287+
return context.bind(parentContext, callback).apply(this, arguments);
282288
};
283289
}
284290

285291
try {
286-
return original.apply(this, arguments);
292+
return context.bind(currentContext, original).apply(this, arguments);
287293
} catch (anyError) {
288294
const [error, message] = asErrorAndMessage(anyError);
289295
span.recordException(error);
@@ -296,7 +302,7 @@ export class ExpressInstrumentation extends InstrumentationBase<ExpressInstrumen
296302
/**
297303
* At this point if the callback wasn't called, that means either the
298304
* layer is asynchronous (so it will call the callback later on) or that
299-
* the layer directly end the http response, so we'll hook into the "finish"
305+
* the layer directly ends the http response, so we'll hook into the "finish"
300306
* event to handle the later case.
301307
*/
302308
if (!spanHasEnded) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ describe('ExpressInstrumentation', () => {
9696
);
9797
assert.strictEqual(response, 'tata');
9898
rootSpan.end();
99-
assert.strictEqual(finishListenerCount, 2);
99+
assert.strictEqual(finishListenerCount, 3);
100100
assert.notStrictEqual(
101101
memoryExporter
102102
.getFinishedSpans()
@@ -201,7 +201,7 @@ describe('ExpressInstrumentation', () => {
201201
);
202202
assert.strictEqual(response, 'tata');
203203
rootSpan.end();
204-
assert.strictEqual(finishListenerCount, 2);
204+
assert.strictEqual(finishListenerCount, 3);
205205
assert.notStrictEqual(
206206
memoryExporter
207207
.getFinishedSpans()

0 commit comments

Comments
 (0)