Loading…
Loading…
Learn how to instrument a Node.js app with OpenTelemetry for traces, metrics, and logs, and build a practical observability setup for production debugging.
Tags
In this tutorial, you will instrument a Node.js service with OpenTelemetry so you can capture traces, metrics, and the request context needed to debug production issues. OpenTelemetry is most useful when you want end-to-end visibility without coupling your application to one monitoring vendor.
Before you begin, you should have:
This tutorial focuses on the instrumentation model, not on a specific vendor backend.
Observability work is easier when you define the signals first.
For a Node.js app, the most useful questions are usually:
Those questions map naturally to:
OpenTelemetry helps you collect those signals in a structured, correlated way.
For a typical Node.js service, start with the SDK and automatic instrumentation packages.
npm install @opentelemetry/sdk-node \
@opentelemetry/auto-instrumentations-node \
@opentelemetry/exporter-trace-otlp-http \
@opentelemetry/resources \
@opentelemetry/semantic-conventionsDepending on your setup, you may also add metrics exporters or framework-specific packages later. The important part is to start with a clean baseline.
Instrumentation should initialize before your application starts serving requests.
// instrumentation.ts
import { NodeSDK } from "@opentelemetry/sdk-node";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
const traceExporter = new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
});
export const sdk = new NodeSDK({
traceExporter,
instrumentations: [getNodeAutoInstrumentations()],
});Then start it before your server boots:
// server.ts
import { sdk } from "./instrumentation";
import { createServer } from "./app";
async function bootstrap() {
await sdk.start();
const app = await createServer();
app.listen(3000);
}
bootstrap();If OpenTelemetry starts too late, you miss spans around application startup and early requests.
Telemetry becomes much more useful when the service identifies itself clearly.
import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
const resource = new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: "billing-api",
[SemanticResourceAttributes.SERVICE_VERSION]: "1.0.0",
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]:
process.env.NODE_ENV ?? "development",
});Without consistent service naming, traces from multiple services become much harder to navigate.
Automatic instrumentation is a good starting point because it captures common framework and client behavior with little code:
That gives you immediate visibility into request chains. For many services, this already surfaces a lot of latency and failure patterns.
Auto-instrumentation is helpful, but it does not know your domain boundaries. Add manual spans where business logic matters.
import { trace } from "@opentelemetry/api";
const tracer = trace.getTracer("orders-service");
export async function processOrder(orderId: string) {
return tracer.startActiveSpan("processOrder", async (span) => {
span.setAttribute("order.id", orderId);
try {
await validateOrder(orderId);
await reserveInventory(orderId);
await capturePayment(orderId);
span.setStatus({ code: 1 });
} catch (error) {
span.recordException(error as Error);
span.setStatus({ code: 2 });
throw error;
} finally {
span.end();
}
});
}This is where traces become useful for product-relevant debugging, not just transport-level timing.
Traces tell you where a request went. Logs tell you what happened in detail.
The most useful production setup links them through shared context such as:
When logs and traces are disconnected, debugging remains slower than it needs to be.
You do not need every possible metric. Start with a few that map directly to operational decisions:
Good observability is not about data volume. It is about making failure modes easier to understand.
Telemetry pipelines can accidentally collect more than they should. Avoid leaking:
Instrumentation should be designed with privacy and security boundaries in mind. Scrubbing and allow-listing are safer defaults than shipping everything.
The real value comes from correlated signals and a consistent instrumentation model, not just one pretty trace view.
If span names, service names, and attributes are inconsistent, the data becomes noisy and hard to use.
A smaller, deliberate set of meaningful spans is usually better than a flood of low-signal telemetry.
Instrumentation adds overhead. In most cases it is acceptable, but you should still measure exporter settings, batching behavior, and sampling choices.
A useful production observability setup often looks like this:
That is enough to make most real Node.js incidents easier to debug.
After the baseline is working, the next improvements usually are:
That is when OpenTelemetry stops being just an instrumentation library and becomes part of how your team operates production systems.
OpenTelemetry is an open standard and ecosystem for collecting telemetry such as traces, metrics, and logs from applications and infrastructure.
It helps teams trace requests across services, monitor latency and failures, and understand production behavior without locking themselves into one vendor.
Not always on day one, but a production-grade setup usually becomes much easier to operate when traces, metrics, and logs are correlated.
Collaboration
I help startups and established companies design, build, and scale world-class digital products. From deep technical architecture to pixel-perfect UI: let's bring your vision to life.
A practical guide to building a Backend-for-Frontend with Next.js and Node.js for API aggregation, auth handling, caching, and frontend-specific data shaping.
A practical CI/CD blueprint for Next.js apps using Docker and GitHub Actions, including testing, image builds, deployment stages, cache strategy, and release safety.
A practical implementation guide for adding OpenTelemetry to Next.js and Node.js apps, including traces, request flow visibility, and production diagnostics.