Monitoring is the difference between "we noticed before the customer did" and "we found out from Twitter." Good observability does not mean having dashboards — it means being able to answer "what is broken, where, and why" in minutes. The 2026 stack is more standardised than ever, with OpenTelemetry as the single collection layer and managed backends that have gotten cheaper and more capable.
What changed in 2026
- OpenTelemetry reached GA for all three signals — metrics, logs, and traces are all stable, and most major frameworks auto-instrument via zero-code agents.
- SLO tooling went mainstream. Sloth, OpenSLO, and built-in SLO features in Datadog, Grafana Cloud, and Google Cloud Monitoring mean teams can define error budgets without custom alerting math.
- AI-assisted anomaly detection is now standard in most managed observability platforms — it reduces the need to hand-tune thresholds on low-signal metrics.
- eBPF-based observability (Cilium, Grafana Beyla) can capture traces and metrics from unmodified binaries at the kernel level — useful for legacy services you cannot recompile.
The three pillars
| Signal |
What it answers |
Storage |
Query |
| Metrics |
"Is the system healthy right now?" |
Time-series DB (Prometheus, Mimir) |
PromQL |
| Logs |
"What exactly happened?" |
Log store (Loki, Elasticsearch) |
LogQL / Lucene |
| Traces |
"Where did the latency go?" |
Trace store (Tempo, Jaeger) |
TraceQL |
Instrument with OpenTelemetry
One SDK, all three signals, any backend:
// Node.js — zero-code auto-instrumentation
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: 'http://otel-collector:4318/v1/traces',
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
Add manual spans for business operations that auto-instrumentation misses:
import { trace } from '@opentelemetry/api';
const tracer = trace.getTracer('order-service');
async function processOrder(orderId: string) {
return tracer.startActiveSpan('processOrder', async (span) => {
span.setAttribute('order.id', orderId);
try {
const result = await doWork(orderId);
span.setStatus({ code: SpanStatusCode.OK });
return result;
} catch (err) {
span.recordException(err as Error);
span.setStatus({ code: SpanStatusCode.ERROR });
throw err;
} finally {
span.end();
}
});
}
The four golden signals
Alert on these, in roughly this priority order:
| Signal |
Description |
PromQL example |
| Error rate |
% requests returning 5xx |
rate(http_requests_total{status=~"5.."}[5m]) |
| Latency |
p99 response time |
histogram_quantile(0.99, rate(http_duration_seconds_bucket[5m])) |
| Saturation |
How full is the system? |
sum(rate(http_requests_total[5m])) / limit |
| Traffic |
Requests per second |
rate(http_requests_total[5m]) |
Structured logging
Unstructured logs are hard to query at scale. Emit JSON:
import pino from 'pino';
const logger = pino();
logger.info(
{ orderId, userId, durationMs: 142 },
'Order payment completed'
);
// {"level":30,"time":...,"orderId":"123","userId":"u456","durationMs":142,"msg":"Order payment completed"}
Always include: trace_id (from the active span context), service.name, environment, and the relevant business entity IDs. This makes log-to-trace correlation instant.
SLOs and alerts
Define what "good" looks like before writing any alert:
# OpenSLO format
apiVersion: openslo/v1
kind: SLO
metadata:
name: orders-api-availability
spec:
service: orders-api
indicator:
metadata:
name: success-rate
spec:
ratioMetric:
good:
metricSource:
type: Prometheus
spec:
query: sum(rate(http_requests_total{status!~"5.."}[5m]))
total:
metricSource:
type: Prometheus
spec:
query: sum(rate(http_requests_total[5m]))
objectives:
- displayName: "99.9% availability"
target: 0.999
timeWindow: 30d
Alert when you are burning your error budget too fast — not on raw error count.
How to pick observability tools
- Greenfield, cloud-native? Grafana Cloud (Prometheus + Loki + Tempo) or Datadog — both are mature, OpenTelemetry-native, and have free tiers.
- AWS-centric? CloudWatch + X-Ray is the path of least resistance; add Managed Prometheus/Grafana if you need richer querying.
- Self-hosted required? Prometheus + Grafana + Loki + Tempo is the canonical open-source stack.
- Small team, low ops budget? Axiom or Better Stack (Logtail) — generous free tiers, zero infrastructure.
- Enterprise with compliance needs? Datadog or New Relic — richer RBAC, audit logs, and SOC 2 certifications.
Common mistakes
Alerting on infrastructure metrics first. High CPU is not an incident; high error rate is. Alert on symptoms; use metrics for diagnosis.
No runbooks. Every alert should link to a runbook that answers "what do I do right now?" without waking someone up to think from scratch.
Missing trace IDs in logs. Without trace_id in log lines, correlating a log event to a trace requires guesswork. Inject it automatically via your logging middleware.
Alert thresholds set on gut feel. Use historical data to set thresholds. If an alert fires every deploy, it is tuned wrong.
No on-call rotation documentation. The monitoring stack is only as good as the humans who respond to it.
What to skip
- A dashboard for every metric. Build dashboards for the four golden signals per service; create others on demand, not speculatively.
- Alerting on every 5xx. Alert on error rate over a window, not individual errors — a brief spike during a deploy should not page anyone.
- Logging sensitive data. PII, tokens, and passwords in log lines are compliance and security liabilities. Scrub before logging.
FAQ
Do I need all three observability pillars for a small service?
Metrics and structured logs get you far. Traces pay off most in microservices or anywhere latency is hard to attribute. Start with metrics + logs; add tracing when you have multi-service calls.
What is the difference between monitoring and observability?
Monitoring answers known questions ("is the error rate too high?"). Observability lets you ask new questions without redeploying ("why is this specific user's request slow?"). You need both.
How many alerts is too many?
If the average alert requires no action more than 10% of the time, it should be removed or downgraded. A handful of high-quality alerts beats dozens of noisy ones.
How do I monitor a serverless function?
Use structured logging with the platform logger (CloudWatch Logs, Vercel Logs), instrument with OpenTelemetry via a layer, and track cold start rate and duration alongside error rate and latency.
Where to go next
See How to profile slow code in 2026, Logging explained in 2026, and How to set up CI/CD in 2026.