Skip to content

instrumentation-http: ESM instrumentation does not work on outgoing requests #5024

@constb

Description

@constb

What happened?

Steps to Reproduce

with node v20.17.0 or v18.20.4, install latest (0.53.0) opentelemetry sdk-node and instrumentation-http
enable ESM (set type: module in package.json)

a client makes a http request in context with trace id using http.request()

Expected Result

server receives traceparent header and runs in a context with same traceId.

Actual Result

server does not receive traceparent header and runs handler in a separate trace context.

Additional Details

might be related to #5001

OpenTelemetry Setup Code

// register.js

import { register } from 'node:module';
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
import { node, NodeSDK } from '@opentelemetry/sdk-node';

const OPENTELEMETRY_SDK = Symbol('openTelemetrySdk');

register('@opentelemetry/instrumentation/hook.mjs', import.meta.url);

globalThis[OPENTELEMETRY_SDK] = new NodeSDK({
  serviceName: 'test',
  instrumentations: [new HttpInstrumentation({ enabled: true })],
});
globalThis[OPENTELEMETRY_SDK].start();

const shutdownFn = async () => globalThis[OPENTELEMETRY_SDK].shutdown().then(() => console.log('shutdown')).catch((error) => console.error(error));
let shutdownStarted = false;
const signals = ['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT', 'SIGBUS', 'SIGFPE', 'SIGSEGV', 'SIGUSR2', 'SIGTERM'];
const signalHandler = (signal) => {
  if (shutdownStarted) return;
  shutdownStarted = true;
  shutdownFn().then(() => {
    signals.forEach((s) => process.removeListener(s, signalHandler));
    process.kill(process.pid, signal);
  });
};
signals.forEach((s) => process.on(s, signalHandler));

// index.js

import { api } from '@opentelemetry/sdk-node';
import http from 'node:http';

const span = api.trace.getTracer().startSpan('test');
const ctx = api.trace.setSpan(api.context.active(), span);

const server = http.Server((req, res) => {
  console.log('server', { heades: req.headers, span: api.trace.getActiveSpan().spanContext() });
  res.writeHead(204);
  res.end();
});
await new Promise(res => server.listen(8080).once('listening', res));

await api.context.with(ctx, async () => {
  console.log('client', { span: api.trace.getActiveSpan().spanContext() });
  await new Promise(resolve => {
    const req = http.request('http://localhost:8080/ping', (res) => {
      res.on('data', () => {});
      res.on('end', resolve);
    });
    req.end();
  });
});

process.kill(process.pid, 'SIGTERM');

package.json

{
  "name": "otel-reproduce",
  "version": "0.0.1",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "cross-env OTEL_PROPAGATORS=tracecontext OTEL_TRACES_EXPORTER=console OTEL_NODE_RESOURCE_DETECTORS=none node --import ./register.js ./index.js"
  },
  "author": "",
  "license": "UNLICENSED",
  "description": "",
  "dependencies": {
    "@opentelemetry/instrumentation": "0.53.0",
    "@opentelemetry/instrumentation-http": "0.53.0",
    "@opentelemetry/sdk-node": "0.53.0",
    "cross-env": "7.0.3"
  }
}

Relevant log output

client {
  span: {
    traceId: '92a751c98e9a4c3d782cc6c877fd8502',
    spanId: '74ae11ca029180a3',
    traceFlags: 1,
    traceState: undefined
  }
}
server {
  heades: { host: 'localhost:8080', connection: 'close' },
  span: {
    traceId: 'c94c82377ce8920746fc79e664303ebc',
    spanId: '64f65ad6b638654a',
    traceFlags: 1,
    traceState: undefined
  }
}

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingpkg:instrumentation-httppriority:p2Bugs and spec inconsistencies which cause telemetry to be incomplete or incorrect

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions