Metrics & Monitoring — DevOps

Observability: Metrics, Logs, Traces Tiga pilar observability: Metrics — Angka terukur seiring waktu (CPU usage, request count, response time) Logs — Event…

Metric adalah angka yang diukur berulang-ulang dan disimpan bersama waktunya, jadi deretan titik yang membentuk grafik (time series). Monitoring artinya memantau angka-angka itu terus-menerus. Bayangin dasbor mobil. Odometer cuma bisa naik: total kilometer sejak mobil dibuat. Speedometer naik turun: kecepatan saat ini. Dan buku catatan perjalanan yang mengelompokkan perjalanan menurut lamanya: berapa yang di bawah 15 menit, berapa yang di bawah 30 menit. Tiga alat itu persis tiga jenis metric: counter, gauge, dan histogram.

Log menceritakan satu kejadian, error tracking mengelompokkan error. Metrics menjawab pertanyaan "seberapa banyak" dan "seberapa cepat" untuk semua request sekaligus, dengan biaya kecil: satu angka per metric, bukan satu baris per request.

🧪 Tebakan cepat: dari 100 request GET /catatan terakhir, 97 selesai dalam 17 sampai 104 ms, dan 3 butuh 2,4 detik karena query dingin. Rata-ratanya sekitar 45 ms, 115 ms, atau 2,4 detik? Dan p50-nya? Jawabannya ada di bagian "Kenapa rata-rata berbohong".

Tiga jenis metric

Jenis Sifatnya Contoh di catatan-api
counter cuma naik, kembali ke 0 saat app restart http_requests_total: request yang sudah dilayani
gauge naik dan turun, yang penting nilainya sekarang http_requests_in_flight: request yang sedang diproses, memori terpakai
histogram menghitung berapa nilai jatuh di tiap bucket http_request_duration_seconds: durasi request

Angka counter sendiri gak berguna; 18.342 request sejak kapan? Yang dibaca kecepatannya: selisih dua pengukuran dibagi jarak waktunya. Histogram menyimpan hitungan per batas atas (le, less or equal): berapa request di bawah 0,05 detik, di bawah 0,1 detik, dan seterusnya. Dari situ persentil diperkirakan.

Persentil: p50, p95, p99

pX adalah durasi yang gak dilewati oleh X% request. p95 = 75 ms artinya 95 dari 100 request selesai dalam 75 ms atau kurang. p50 juga disebut median: titik tengah. Cara menghitungnya (metode nearest rank):

function calculatePercentile(values, percentile) {
  const sorted = [...values].sort((a, b) => a - b); // salinan, urut naik
  const index = Math.ceil((percentile * sorted.length) / 100) - 1;
  return sorted[index];
}
Panggilan Urutan Posisi Hasil
calculatePercentile([10, 20, 30, 40, 50], 50) 10 20 30 40 50 ceil(2,5) - 1 = 2 30
calculatePercentile([10, 20, 30, 40, 50], 95) 10 20 30 40 50 ceil(4,75) - 1 = 4 50
calculatePercentile([5, 3, 1, 4, 2], 20) 1 2 3 4 5 ceil(1) - 1 = 0 1

Prometheus menghitung persentil dari bucket histogram dengan histogram_quantile, jadi hasilnya perkiraan, tapi artinya sama.

Kenapa rata-rata berbohong

Ini 100 request di Lab, sebelum dan sesudah 3 di antaranya kena query dingin 2,4 detik:

rata-rata p50 p95 p99
tanpa request lambat 45,0 ms 43 ms 68 ms 80 ms
3 request 2.400 ms 115,5 ms 43 ms 75 ms 2.400 ms

Rata-ratanya 115,5 ms dan p50-nya tetap 43 ms. Itu jawaban tebakannya. Padahal gak ada satu request pun yang butuh 115 ms: 97 request di bawah 105 ms, dan 3 request 2.400 ms. Rata-rata mencampur dua kelompok jadi angka yang gak menggambarkan siapa pun. p50 gak bergeser, karena median gak peduli seberapa lambat ekornya. p99 yang menangkapnya: lebih dari 1 dari 100 user menunggu 2,4 detik. Karena itu latency dipantau di p95 dan p99, ditemani p50.

RED, USE, dan four golden signals

Supaya gak tenggelam di ratusan metric, ada tiga daftar pegangan:

Monitoring menjawab pertanyaan yang sudah kamu tahu sebelumnya: "apakah error rate di atas 5%?", lewat dashboard dan alert. Observability adalah kemampuan menjawab pertanyaan baru yang belum terpikir: "kenapa cuma request user di Surabaya yang lambat?", dengan menggabungkan metrics, log, dan trace. Trace dibahas di pelajaran OpenTelemetry Fundamentals dan Distributed Tracing.

Prometheus: scrape /metrics

catatan-api menyediakan semua angkanya di satu halaman, /metrics, dengan library prom-client:

const client = require("prom-client");
client.collectDefaultMetrics(); // memori, CPU, event loop Node

const requests = new client.Counter({ name: "http_requests_total", help: "Total HTTP requests", labelNames: ["method", "route", "status_code"] });
const inFlight = new client.Gauge({ name: "http_requests_in_flight", help: "Requests being handled right now" });
const duration = new client.Histogram({ name: "http_request_duration_seconds", help: "Request duration in seconds", labelNames: ["route"], buckets: [0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5] });

app.use((req, res, next) => {
  inFlight.inc();
  const end = duration.startTimer();
  res.on("finish", () => {
    const route = req.route ? req.route.path : req.path;
    requests.inc({ method: req.method, route, status_code: res.statusCode });
    end({ route });
    inFlight.dec();
  });
  next();
});

app.get("/metrics", async (req, res) => {
  res.set("Content-Type", client.register.contentType);
  res.end(await client.register.metrics());
});

Prometheus lalu datang mengambil halaman itu setiap 15 detik. Ini disebut scrape, model pull: app gak mengirim apa-apa, Prometheus yang menarik. Config-nya di prometheus.yml, dengan Prometheus jalan sebagai service lain di Compose yang sama:

scrape_configs:
  - job_name: catatan-api
    scrape_interval: 15s
    static_configs:
      - targets: ["app:3000"]   # path default: /metrics

Sebagian isi /metrics yang ditarik:

# TYPE http_requests_total counter
http_requests_total{method="GET",route="/catatan",status_code="200"} 18342
# TYPE http_requests_in_flight gauge
http_requests_in_flight 3
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.05",route="/catatan"} 72
http_request_duration_seconds_bucket{le="0.1",route="/catatan"} 99
http_request_duration_seconds_bucket{le="+Inf",route="/catatan"} 100

15 detik kemudian counter-nya 18.524, jadi kecepatannya (18.524 - 18.342) / 15 = 12,1 request per detik. Di PromQL, bahasa query Prometheus, itu rate(http_requests_total[1m]). Grafana lalu menggambar angka-angka Prometheus jadi dashboard. Prometheus + Grafana adalah pasangan open source paling umum untuk ini; cara memasangnya ada di pelajaran Grafana & Prometheus Setup.

⚠️ Jebakan yang sering ketemu

TL;DR: Metric adalah angka yang diukur berkala jadi time series. Counter cuma naik (dibaca dengan rate()), gauge naik turun (nilainya sekarang), histogram menghitung nilai per bucket untuk persentil. pX = durasi yang gak dilewati X% request; dengan nearest rank: urutkan salinannya pakai (a, b) => a - b, ambil index Math.ceil(percentile * n / 100) - 1. Rata-rata berbohong untuk latency: 3 request 2,4 detik membuat rata-rata 115,5 ms padahal p50 tetap 43 ms, dan cuma p99 (2.400 ms) yang menangkap ekornya. RED (rate, errors, duration) untuk service, USE (utilization, saturation, errors) untuk resource, four golden signals: latency, traffic, errors, saturation. Monitoring mengecek masalah yang sudah dikenal, observability membantu memahami masalah baru. Prometheus men-scrape /metrics tiap 15 detik, Grafana menggambarnya jadi dashboard.

Yang akan kamu pelajari