Chapter 15 — Monitoring, Logging & Observability

If you can't see what's happening in production, you can't fix it. Observability is the ability to understand your system's internal state from its external outputs.

The Three Pillars

PillarWhatToolsAnswers
MetricsNumeric measurements over timePrometheus, CloudWatch, Datadog"How much?" "How fast?" "How often?"
LogsDiscrete events with contextLoki, ELK, CloudWatch Logs"What happened?" "Why did it fail?"
TracesRequest flow across servicesJaeger, Zipkin, AWS X-Ray"Where is the bottleneck?" "Which service is slow?"

Prometheus + Grafana (The Open-Source Standard)

# docker-compose.yml — Monitoring stack
services:
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    ports:
      - "9090:9090"
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=30d'

  grafana:
    image: grafana/grafana:latest
    volumes:
      - grafana_data:/var/lib/grafana
    ports:
      - "3001:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: changeme

  node-exporter:
    image: prom/node-exporter:latest
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro

volumes:
  prometheus_data:
  grafana_data:
# prometheus.yml — Scrape configuration
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "alerts.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']

  - job_name: 'myapp'
    static_configs:
      - targets: ['myapp:3000']
    metrics_path: '/metrics'

Application Metrics (What to Measure)

The RED method for services and USE method for resources:

MethodMetricWhat It Tells You
RED (Services)RateRequests per second
ErrorsFailed requests per second
DurationResponse time (p50, p95, p99)
USE (Resources)Utilization% of resource capacity used
SaturationQueue depth, waiting work
ErrorsError count on the resource
# Example: Exposing metrics in Node.js (using prom-client)
const client = require('prom-client');

// Default metrics (CPU, memory, event loop)
client.collectDefaultMetrics();

// Custom metrics
const httpRequestDuration = new client.Histogram({
  name: 'http_request_duration_seconds',
  help: 'Duration of HTTP requests in seconds',
  labelNames: ['method', 'route', 'status_code'],
  buckets: [0.01, 0.05, 0.1, 0.5, 1, 5]
});

// Middleware to track requests
app.use((req, res, next) => {
  const end = httpRequestDuration.startTimer();
  res.on('finish', () => {
    end({ method: req.method, route: req.route?.path || req.path, status_code: res.statusCode });
  });
  next();
});

// Metrics endpoint for Prometheus to scrape
app.get('/metrics', async (req, res) => {
  res.set('Content-Type', client.register.contentType);
  res.end(await client.register.metrics());
});

Alerting Rules

# alerts.yml — Prometheus alerting rules
groups:
  - name: webapp
    rules:
      - alert: HighErrorRate
        expr: rate(http_requests_total{status_code=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High error rate (> 5%)"
          description: "{{ $labels.instance }} has {{ $value | humanizePercentage }} error rate"

      - alert: HighLatency
        expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 2
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High p95 latency (> 2s)"

      - alert: InstanceDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Instance {{ $labels.instance }} is down"

SLIs, SLOs, and SLAs

TermDefinitionExample
SLI (Indicator)A measurable metric of service quality99.2% of requests complete in <500ms
SLO (Objective)Target value for an SLI (internal goal)"99.9% availability over 30 days"
SLA (Agreement)Contract with customers (with consequences)"99.9% uptime or we credit your bill"
Error budgets: If your SLO is 99.9% uptime (43 minutes downtime/month), you have a 0.1% "error budget." Use it for deployments, experiments, and maintenance. When the budget is exhausted, freeze deployments and focus on reliability.