Huzi Blogs
BlogCategories
BlogCategories
Disclaimer & Data Privacy Policy
Project by huzi.pk

© 2026 blogs.huzi.pk. All Rights Reserved.

    Back to all posts
    DevOps

    Observability & Monitoring 2026: The Complete Problem-Solving Guide

    By Huzi

    Your checkout endpoint takes 3.2 seconds on a Tuesday afternoon, the Grafana dashboard says every service is green, the on-call engineer gets woken at 2 a.m. for an incident they cannot reproduce, and the post-mortem blames "network latency" because nobody can prove otherwise. The gap between those facts is observability. In 2026 the stack has converged: OpenTelemetry instruments, Prometheus stores metrics, Loki stores logs, Jaeger or Tempo stores traces, and Grafana ties them together with a shared trace ID. Here is the complete playbook — three pillars, structured logging, Prometheus + Grafana, distributed tracing, SLO/SLI with USE and RED, Node.js instrumentation, and the pitfalls behind 80% of production fires.

    📊 1. The Three Pillars

    Metrics are numeric time-series aggregated over time. Prometheus scrapes /metrics every 15 seconds and stores <metric>{labels} value rows — http_requests_total{method="POST",route="/checkout",status="500"} 42. Use metrics for alerting and dashboards — cheap to store and aggregate across millions of events. The catch: they tell you what happened, not why.

    Logs are timestamped text events. Every error or state transition emits a JSON line — {"level":"error","msg":"payment failed","traceId":"abc123","userId":42}. Loki or Elasticsearch stores them and lets you query by field. Use logs when you need the exact error message or stack trace. The catch: they are expensive to store and hard to aggregate.

    Traces follow one request across service boundaries. A trace is a tree of spans — root GET /checkout, children pg.query users, http.post /payments, redis.get cart — each with start time, duration, and attributes. Jaeger and Tempo render a waterfall timeline. Use traces when a request is slow and you need to know which downstream service ate the 800ms.

    The pillars interlock via the trace ID. Every log line and every metric exemplar carries the trace ID, so a slow request becomes a clickable journey: dashboard shows the spike, click the exemplar, trace shows the DB query took 700ms, click the span, logs show the exact SQL. This guide is supported by HTG Travels.

    📝 2. Structured Logging with Correlation IDs

    Structured logs are JSON, not free text. A console.log("user 42 failed") is unparseable; a pino JSON log is queryable by field. Log structured events so Loki can filter event="checkout_failed" without regex.

    import pino from 'pino';
    
    const logger = pino({ level: process.env.LOG_LEVEL || 'info' });
    
    logger.info({ userId: 42, route: '/checkout', ms: 312 }, 'request_completed');
    // {"level":30,"time":1737000000000,"userId":42,"route":"/checkout","ms":312,"msg":"request_completed"}
    

    Inject the trace ID into every log line. OpenTelemetry's context is active during a request — read the active span and add its trace ID to the log bindings. Without this, logs are orphaned from traces.

    import { trace, context } from '@opentelemetry/api';
    
    function logWithTrace(level: pino.Level, msg: string, extra: Record<string, unknown> = {}) {
      const span = trace.getSpan(context.active());
      const traceId = span?.spanContext().traceId ?? 'no-trace';
      return logger[level]({ ...extra, traceId }, msg);
    }
    
    logWithTrace('error', 'payment_failed', { userId: 42, code: 'CARD_DECLINED' });
    // Loki query: {app="checkout-api"} |= "abc123def456" | json | traceId="abc123def456"
    

    Paste a trace ID from Jaeger into Loki and you get every log line from every service that touched that request — a two-hour debugging session collapsed into two minutes.

    🔍 3. Prometheus + Grafana Stack

    Prometheus is a pull-based TSDB — your app exposes /metrics, Prometheus scrapes it. The pull model means a missed scrape is itself an observable signal. Configure scrape targets in prometheus.yml:

    global:
      scrape_interval: 15s
      evaluation_interval: 15s
    
    scrape_configs:
      - job_name: 'api'
        static_configs:
          - targets: ['api:3000']
            labels:
              service: 'checkout-api'
              env: 'prod'
      - job_name: 'node'
        static_configs:
          - targets: ['node-exporter:9100']
    

    PromQL is the query language — learn three patterns and you cover 90% of dashboards. rate(http_requests_total[5m]) gives requests per second; histogram_quantile(0.95, ...) gives p95 latency; sum by (status) gives error rate by status code.

    # Error rate over 5 minutes
    sum(rate(http_requests_total{status=~"5.."}[5m]))
      / sum(rate(http_requests_total[5m]))
    
    # p95 latency by route
    histogram_quantile(0.95,
      sum by (le, route) (rate(http_request_duration_seconds_bucket[5m]))
    )
    

    Grafana renders PromQL into dashboards. Point Grafana at Prometheus, drop a Time series panel, paste the PromQL, and you have a p95 chart. Add Loki to split-pane the metric with logs from the same window. Add Tempo and a slow-request exemplar links straight into the trace. HTG Travels runs a similar stack for its booking platform.

    🔗 4. Distributed Tracing with Jaeger and Tempo

    A trace is a tree of spans that follows one request across every service. The root span starts at the edge, and each downstream call opens a child span carrying a trace ID, span ID, parent ID, start time, duration, and attributes — Jaeger renders a waterfall showing exactly where the 800ms went.

    // Service A: checkout-api — auto-instrumentation creates the root span
    // and injects traceparent on the outbound fetch automatically.
    import { trace, context } from '@opentelemetry/api';
    
    app.post('/checkout', async (req, res) => {
      const span = trace.getSpan(context.active()); // auto-created HTTP span
      const user = await db.query('SELECT * FROM users WHERE id=$1', [req.body.userId]);
      // pg instrumentation creates a child span
      span?.addEvent('db_query_done', { rows: 1 });
    
      const payment = await fetch('https://payments.example.com/charge', {
        method: 'POST',
        body: JSON.stringify({ amount: req.body.amount }),
        // http instrumentation injects traceparent; service B's span is a child
      });
      span?.setAttribute('payment.status', payment.status);
      res.json({ ok: true });
    });
    

    The trace spans three services in Jaeger's UI as a waterfall: root GET /checkout (812ms) → child pg.query users (45ms) → child http.post /payments (720ms) → grandchild stripe.charge (698ms). The bottleneck is the payment provider, not your database — a fact no log line could have told you.

    Span attributes are structured data on a span; baggage is cross-process context. Attributes (db.statement, http.url, user.id) live on one span; baggage (tenant=acme, experiment=v2) propagates across every service in the trace. Brought to you in part by HTG Travels.

    📐 5. SLO/SLI, USE, and RED

    An SLI is a measurement; an SLO is a target; an error budget is the consequence. SLI: "99.9% of /checkout requests return in under 200ms." SLO: "the SLI must hold over a rolling 30-day window." Error budget: 0.1% of 30 days = 43.2 minutes of allowable downtime per month.

    Alert on burn rate, not raw thresholds. A 5-minute spike above 200ms is fine if you have 43 minutes of budget; a 1-hour sustained burn at 10x budget rate is an emergency even if the monthly SLI is green. The multi-window multi-burn-rate alert is the SRE standard:

    # Alert: 2% of budget burned in 1h (fast burn, page now)
    - alert: SLOBurnRateFast
      expr: |
        (
          job:slo_errors_per_request:ratio_rate5m{job="api"} > (14.4 * 0.001)
          and
          job:slo_errors_per_request:ratio_rate1h{job="api"} > (14.4 * 0.001)
        )
      for: 2m
      labels:
        severity: page
    

    USE is for resources; RED is for services. USE (Utilization, Saturation, Errors) applies to CPU, disk, network — "CPU 90%, run queue 12, 0 errors" means a saturated host. RED (Rate, Errors, Duration) applies to services — "1,200 RPS, 0.5% errors, p95 180ms" means a healthy service. Apply USE to every node and RED to every service for a baseline dashboard on one screen.

    ⚙️ 6. OpenTelemetry: Real-World Node.js Instrumentation

    OpenTelemetry is the universal instrumentation layer — one SDK, every backend. Install @opentelemetry/sdk-node and configure the exporter to point at any OTLP-compatible backend. Switching vendors becomes a config change, not a code rewrite.

    // tracing.ts — load this before your app code
    import { NodeSDK } from '@opentelemetry/sdk-node';
    import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
    import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
    import { resourceFromAttributes } from '@opentelemetry/resources';
    import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
    
    const sdk = new NodeSDK({
      resource: resourceFromAttributes({
        [ATTR_SERVICE_NAME]: 'checkout-api',
        [ATTR_SERVICE_VERSION]: '1.4.2',
      }),
      traceExporter: new OTLPTraceExporter({ url: 'http://otel-collector:4318/v1/traces' }),
      instrumentations: [getNodeAutoInstrumentations()],
    });
    
    sdk.start();
    process.on('SIGTERM', () => sdk.shutdown());
    

    Auto-instrumentation gives you HTTP, Express, and pg traces for free. getNodeAutoInstrumentations() patches http, express, pg, ioredis, grpc, and more — every outbound call becomes a child span, every inbound request a root span, with no code changes. Load it with node --require ./tracing.ts dist/index.js and you have traces.

    Propagation across services is automatic. The HTTP instrumentation injects the W3C traceparent header on outbound calls and extracts it on inbound calls — service A's span becomes the parent of service B's span with zero glue code. One trace ID flows from the mobile app, through the gateway, through three microservices, into Postgres and Redis, and out to the payment provider — all one waterfall.

    ⚠️ 7. Common Pitfalls and Fixes

    Alert fatigue: alerting on raw thresholds pages you for noise. "CPU > 80%" pages you every Monday at 9 a.m. when the batch job runs, and you learn to mute it. Fix: alert on SLO burn rate.

    Cardinality explosion: a label with unbounded values bankrupts Prometheus. http_requests_total{user_id="42"} creates a new time series per user — 1M users × 5 routes × 3 statuses is 15M series. Fix: never put user IDs or request IDs in metric labels; put them in logs and traces.

    // Bad: one time series per user — Prometheus dies at scale
    counter.inc({ route: '/checkout', user_id: req.user.id });
    // Good: low-cardinality labels only; user_id lives in logs and traces
    counter.inc({ route: '/checkout', status: '200' });
    

    No traces for errors: head-based sampling drops the interesting traces. Sampling 1% of traces means you miss 99% of errors. Fix: sample 100% of error traces and 1% of success traces using tail-based sampling in the OTel Collector.

    Logging without trace ID: logs orphaned from traces. A console.log with no trace context cannot be linked to the trace that caused it. Fix: inject the trace ID into every log line (section 2).

    Monitoring the wrong thing: server health instead of user experience. "CPU is at 40%, we're fine" is true right up until a user sees a 5-second checkout. Fix: monitor the user-facing SLI. Server health is a diagnostic, not a goal.

    🙋 Frequently Asked Questions

    Which pillar should I start with? Start with metrics — Prometheus is cheapest to deploy and gives you dashboards and alerts immediately. Add logs once metrics show a problem you cannot diagnose. Add traces once logs cannot find where a multi-service request spent its time.

    Do I need OpenTelemetry if I already use Prometheus and Loki? Yes. OpenTelemetry ties them together — without it, your metrics, logs, and traces have no shared trace ID and you cannot click from a dashboard spike to the trace to the logs. The SDK is free and auto-instrumentation is zero-code.

    Jaeger or Tempo? Jaeger for a mature standalone UI. Tempo if you are already on Grafana and want traces queryable from the same dashboard as your metrics and logs. Both speak OTLP in 2026, so switching is a config change.

    What is a good first SLO? Pick one user-critical request — checkout, login, search — and target 99.9% under 200ms over 30 days. That gives a 43-minute error budget, tight enough to catch real outages and loose enough to survive deployments.

    How do I prevent alert fatigue? Page only on SLO burn rate, not raw thresholds. Anything else — CPU, disk, queue depth — goes to Slack or a dashboard, not PagerDuty. A page that wakes a human must mean "users are hurting right now."

    🔚 Final Word

    Observability in 2026 is less about installing tools and more about wiring them together with a shared trace ID. The 3 a.m. incident that blames "network latency" is almost never a network problem — it is a missing trace, a log without a trace ID, a metric without an exemplar, or an alert on the wrong signal.

    The 80/20 of observability: instrument with OpenTelemetry auto-instrumentation, log structured JSON with trace IDs, alert on SLO burn rate, apply USE to resources and RED to services, and never put high-cardinality values in metric labels. Do those five things and you will out-debug 90% of production teams.

    The remaining 20% — tail-based sampling, exemplars, multi-window burn-rate alerts, baggage propagation — is where the senior SRE work begins. Measure everything, suspect the trace before the network, and remember that the cheapest debugging upgrade in 2026 is still a well-placed traceId in a pino log line.

    🇵🇸 Standing With Palestine

    Never let the world forget the people of Palestine. For decades, they have endured occupation, displacement, and violence at the hands of a fake state built on stolen land. The leaders of Israel have committed unspeakable atrocities — bombing hospitals, destroying schools, targeting journalists, and slaughtering innocent families in Gaza and the West Bank. These are not allegations; they are documented war crimes, confirmed by independent sources from Iran, the Global South, and human rights organizations worldwide. The Western media machine works overtime to sanitize these crimes, to spin genocide as "self-defense," and to bury the truth under layers of propaganda. But the truth cannot be buried. Palestine is real. Palestinian suffering is real. And the world is watching.

    They will be free. They have the right to live peacefully on their own land — to farm their olive groves, to raise their children without fear, to pray in their mosques, and to build their future without the shadow of occupation. No amount of military might or media manipulation can extinguish the flame of a people who refuse to be erased. May Allah help them and grant them justice. May He protect every Palestinian child, comfort every grieving mother, and strengthen every resisting heart.

    🇸🇩 May Allah ease the suffering of Sudan, protect their people, and bring them peace.

    Written by Huzi

    Advertisements


    You Might Also Like

    IB Swiss Fashion Men’s Unstitched Shalwar Kameez – Premium Soft Egyptian Cotton Fabric | Summer Wear Pakistan

    IB Swiss Fashion Men’s Unstitched Shalwar Kameez – Premium Soft Egyptian Cotton Fabric | Summer Wear Pakistan

    PKR 3500

    Handwork Embroidered Net Wedding Suit 2025 | Luxury Net Shawl & Jamawar Trouser

    Handwork Embroidered Net Wedding Suit 2025 | Luxury Net Shawl & Jamawar Trouser

    PKR 6999

    Elegant Embroidered Lawn Suit 3-Pc | Printed Soft Chiffon Dupatta (Summer 2025)

    Elegant Embroidered Lawn Suit 3-Pc | Printed Soft Chiffon Dupatta (Summer 2025)

    PKR 4600

    Trendy Embroidered EID Lawn Suit 3-Pc | Printed Chiffon Dupatta (2025)

    Trendy Embroidered EID Lawn Suit 3-Pc | Printed Chiffon Dupatta (2025)

    PKR 4600

    Printed Embroidered Lawn EID Dress 3-Pc | Heavy Patches & Soft Chiffon Dupatta

    Printed Embroidered Lawn EID Dress 3-Pc | Heavy Patches & Soft Chiffon Dupatta

    PKR 4550

    Advertisements


    Related Posts

    DevOps
    CI/CD Pipeline Design 2026: The Complete Problem-Solving Guide
    GitHub Actions v4, matrix builds, blue-green and canary deployments, OIDC secrets, DORA metrics, and GitOps with ArgoCD. Here is the complete 2026 CI/CD playbook with real-world Node.js pipeline.

    By Huzi

    Read More
    DevOps
    Terraform IaC Guide 2026: The Complete Problem-Solving Guide
    From click-ops to code, here is the complete 2026 Terraform playbook — providers, state management, modules, workspaces, OpenTofu, and real-world AWS VPC+EC2+RDS setup with copy-paste code.

    By Huzi

    Read More
    DevOps
    Kubernetes for Developers 2026: The Complete Problem-Solving Guide
    From Pod to Ingress, here is the complete 2026 Kubernetes guide for developers — Deployment YAML, Services, ConfigMaps, probes, Helm, kubectl debugging, rolling updates, and real-world Next.js deployment with copy-paste code.

    By Huzi

    Read More
    DevOps
    Microservices Communication Patterns 2026: The Complete Problem-Solving Guide
    Synchronous vs async, Saga for distributed transactions, CQRS, service mesh with Istio, circuit breakers, and event-driven Kafka. Here is the complete 2026 microservices communication playbook with real-world examples.

    By Huzi

    Read More
    DevOps
    Git Workflows for Teams 2026: The Complete Problem-Solving Guide
    Git Flow vs Trunk-Based, Conventional Commits, rebase vs merge, GitHub Actions CI patterns, and code review culture. Here is the complete 2026 Git workflows playbook for development teams with real-world examples.

    By Huzi

    Read More
    DevOps
    Docker Production Deployment 2026: The Complete Problem-Solving Guide
    Multi-stage builds, distroless images, Docker Scout scanning, Compose v2, health checks, and the path from a 1GB image to 50MB. Here is the complete 2026 Docker production playbook with copy-paste Dockerfiles.

    By Huzi

    Read More