Skip to main content
Juliano Alves
Back to blog

OpenTelemetry tracing in Node.js services

3 min read
By Juliano Alves

OpenTelemetry standardizes traces, metrics, and logs so backends (Jaeger, Grafana Tempo, Honeycomb, Datadog) ingest the same data model. In Node, @opentelemetry/sdk-node plus auto-instrumentation gets you HTTP spans quickly; custom spans document business operations.

Bootstrapping#

Load instrumentation before other imports:

// instrumentation.ts (loaded first)
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

Custom spans#

import { trace } from '@opentelemetry/api';

const tracer = trace.getTracer('checkout');
await tracer.startActiveSpan('capture_payment', async (span) => {
  try {
    span.setAttribute('order.id', orderId);
    await charge();
  } catch (e) {
    span.recordException(e);
    throw e;
  } finally {
    span.end();
  }
});

Attributes become queryable dimensions in your trace UI.

Sampling#

100% trace volume is expensive. Use parent-based or ratio sampling in production, with higher rates for error traces or specific routes (tail sampling if your vendor supports it).

Propagation#

Ensure fetch/undici and your HTTP client propagate traceparent headers to downstream services so spans stitch into one trace.

Summary#

OpenTelemetry is the lingua franca of observability. Start with auto-instrumentation, add business spans at critical paths, and tune sampling so telemetry cost scales with value—not raw request volume alone.

© 2026 Juliano Alves. All rights reserved.