gotchajavascriptMajor
OpenTelemetry SDK setup in Node.js requires instrumentation before app imports
Viewed 0 times
@opentelemetry/sdk-node ^0.52
opentelemetryotel sdkauto-instrumentationnode requiretracing setupOTLP exporterNodeSDK
nodejs
Problem
OpenTelemetry auto-instrumentation silently fails to capture spans for http, express, or database calls because the SDK is initialized after the application modules are already imported. Traces appear empty or missing entirely in the backend.
Solution
Create a dedicated tracing.js file that initializes the SDK and registers instrumentation, then require it first via node --require ./tracing.js or as the very first import in your entrypoint before any other module.
Then start your app:
// tracing.js — must be loaded first
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/traces',
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
process.on('SIGTERM', () => sdk.shutdown());Then start your app:
node --require ./tracing.js server.jsWhy
Node.js module caching means that once a module is loaded, its constructor code has already run. OTel patches modules at require-time by monkey-patching their exports, so if the target library is already in the module cache before the patch is applied, the patch never takes effect.
Gotchas
- ES modules (import syntax) require a different loader approach via --experimental-loader, not --require
- OTEL_EXPORTER_OTLP_ENDPOINT must include the full path including /v1/traces for HTTP exporter
- sdk.start() is synchronous for registration but asynchronous internally — don't await it
- Auto-instrumentation can significantly increase memory and CPU; disable unused instrumentations with { enabled: false }
Code Snippets
Correct way to inject tracing before app code
// package.json start script
{
"scripts": {
"start": "node --require ./tracing.js server.js"
}
}Context
Setting up distributed tracing in a Node.js service for the first time
Revisions (0)
No revisions yet.