Observability Practices: The 3 Pillars with a Node.js + OpenTelemetry Example
These articles are AI-generated summaries. Please check the original sources for full details.
Observability Practices: The 3 Pillars with a Node.js + OpenTelemetry Example
In the modern era of distributed systems, relying solely on traditional monitoring is like diagnosing a complex illness with only a thermometer. Observability provides the tools to understand why problems occur, not just when.
Why This Matters
Traditional monitoring tells you “CPU usage is high” but fails to explain why or where the issue originated. In microservices, a single user action can trigger dozens of interdependent calls across languages and platforms. Without observability, debugging unknown failures becomes a guessing game, increasing Mean Time To Resolution (MTTR) and operational costs. Observability bridges this gap by enabling arbitrary questions about system behavior through metrics, logs, and traces.
Key Insights
- “Metrics, logs, and traces form the three pillars of observability” (Wsalas651, 2025)
- “OpenTelemetry enables vendor-neutral instrumentation for traces and metrics” (OpenTelemetry documentation)
- “Prometheus and Grafana provide real-time visualization of system health” (Prometheus, Grafana)
Working Example
// app/src/tracer.js
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
function setupTracing(serviceName = 'observability-demo-app') {
const exporter = new JaegerExporter({
endpoint: 'http://jaeger:14268/api/traces'
});
const sdk = new NodeSDK({
traceExporter: exporter,
instrumentations: [getNodeAutoInstrumentations()],
serviceName
});
sdk.start()
.then(() => console.log('OpenTelemetry initialized'))
.catch(err => console.error('Error starting OpenTelemetry SDK', err));
process.on('SIGTERM', () => sdk.shutdown().catch(e => console.log('Error terminating tracing', e)));
}
module.exports = { setupTracing };
// app/src/metrics.js
const client = require('prom-client');
client.collectDefaultMetrics({ timeout: 5000 });
const register = client.register;
const httpRequestCounter = new client.Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'route', 'status']
});
const httpRequestDuration = new client.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status'],
buckets: [0.005, 0.01, 0.05, 0.1, 0.3, 1, 3, 5]
});
function metricsMiddleware(req, res, next) {
const end = httpRequestDuration.startTimer();
res.on('finish', () => {
const route = req.route ? req.route.path : req.path;
httpRequestCounter.inc({ method: req.method, route, status: res.statusCode });
end({ method: req.method, route, status: res.statusCode });
});
next();
}
module.exports = { register, metricsMiddleware };
Practical Applications
- Use Case: Node.js Express API with OpenTelemetry tracing and Prometheus metrics
- Pitfall: Skipping instrumenting critical services leads to incomplete traces and undetected bottlenecks
References:
Continue reading
Next article
Online Meetings Can't Eliminate the Need to Be in the Office
Related Content
OpenTelemetry Standardizes Cloud Observability Across Distributed Systems
OpenTelemetry establishes a unified standard for metrics, logs, and traces, eliminating vendor lock-in for complex distributed cloud environments.
OtlpDashboard: Consolidating the Observability Stack into a Single Container
Andrea Ficarra introduces OtlpDashboard, a single-container alternative to the Grafana, Loki, Tempo, and Prometheus stack for OTLP telemetry.
The Shift to Distributed Tracing: How OpenTelemetry Standardized Observability
Distributed tracing replaces logs as the primary source of truth, reducing debugging time from 4 hours to 15 minutes via OpenTelemetry.