Aplikasi yang dideploy dan kemudian dibiarkan bukan sistem yang sehat, melainkan sistem yang tidak diketahui kondisinya. Tanpa monitoring, kita mengetahui adanya gangguan dari keluhan pengguna — sumber informasi paling lambat dan paling memalukan. Chapter terakhir ini merangkai tiga fondasi observability untuk aplikasi Python: health check yang bisa dipanggil platform, log terstruktur, error tracking, dan metrik — lalu menutup dengan filosofi alerting.

Apa yang Dipantau #

Metodologi RED merangkum tiga sinyal terpenting layanan online:

SinyalPertanyaanContoh pengukuran
Rateseberapa banyak permintaan?permintaan per detik
Errorsberapa banyak yang gagal?persentase respons 5xx
Durationberapa lama diproses?percentile latency (p95, p99)

Tiga sinyal ini cukup untuk menjawab “apakah pengguna sedang menderita?”. Sinyal keempat — saturation, seberapa penuh sumber daya (CPU, memori, koneksi) — menjelaskan penyebabnya sebelum sistem benar-benar tumbang.

Endpoint healthz #

Health check adalah endpoint ringan yang menjawab “apakah proses ini hidup dan fungsinya bekerja”. Mari kita bangunnya di FastAPI dan mengujinya tanpa menjalankan server, memakai TestClient:

python
from fastapi import FastAPI
from fastapi.testclient import TestClient

app = FastAPI()


def cek_database() -> bool:
    """Simulasi ping database; anggap selalu berhasil."""
    return True


@app.get("/healthz")
def healthz() -> dict[str, str]:
    if not cek_database():
        return {"status": "unhealthy"}
    return {"status": "ok"}


client = TestClient(app)
response = client.get("/healthz")
print(response.status_code)
print(response.json())

Output yang Dihasilkan:

text
200
{'status': 'ok'}

Mari kita telaah keputusan desainnya:

  1. cek_database(): health check yang bermakna menguji dependensi, bukan sekadar mengembalikan "ok" — proses yang hidup namun kehilangan database harus dilaporkan tidak sehat.
  2. Path /healthz: konvensi umum; platform seperti Docker (healthcheck) dan load balancer memeriksanya secara berkala.
  3. TestClient: seluruh endpoint diuji sebagai test otomatis, tanpa port dan tanpa server yang menggantung.

Log Terstruktur #

Di satu server, log teks bebas sulit dicari. Di klaster dengan puluhan container, log harus berbentuk data — satu baris JSON per kejadian. Chapter Structured Logging membahas pembentukannya dengan module logging; prinsip intinya dapat dilihat dari satu baris yang dihasilkan json.dumps:

python
import json

log = {
    "timestamp": "2025-06-15T08:30:00+07:00",
    "level": "INFO",
    "event": "request_selesai",
    "path": "/produk",
    "durasi_ms": 42,
}
print(json.dumps(log))

Output yang Dihasilkan:

text
{"timestamp": "2025-06-15T08:30:00+07:00", "level": "INFO", "event": "request_selesai", "path": "/produk", "durasi_ms": 42}

Sistem agregasi log (ELK, Loki) kemudian dapat memfilter event = "request_selesai" dan menghitung durasi_ms per path — sinyal Duration dari tabel RED lahir dari sini.

Error Tracking dengan Sentry #

Traceback di log bagus untuk forensik, tetapi error tracking mengelompokkan error berulang dan memberi tahu tim lewat email atau Slack. Layanan paling populer untuk ini adalah Sentry, dengan SDK sentry-sdk (ilustratif — SDK ini tidak terpasang di lingkungan pengujian materi ini):

python
import sentry_sdk

sentry_sdk.init(dsn="https://[email protected]/456")

Satu baris inisialisasi tersebut memasang hook pada exception yang tidak tertangani: traceback lengkap, nilai variabel lokal, dan URL peminta terkirim ke dasbor Sentry secara otomatis. Error yang sama dari banyak pengguna terkelompok sebagai satu issue dengan hitungan kemunculan.

Metrik Format Prometheus #

Prometheus menjadi standar de facto untuk metrik, dengan format teks yang sangat sederhana: nama_metrik{label="nilai"} angka. Berikut pengekspos berbasis dictionary biasa — inti dari apa yang dilakukan library prometheus_client:

python
"""Eksposur metrik format teks Prometheus tanpa library tambahan."""

counter_request: dict[str, int] = {}


def catat_request(path: str) -> None:
    counter_request[path] = counter_request.get(path, 0) + 1


def render_metrik() -> str:
    baris = []
    for path, jumlah in sorted(counter_request.items()):
        nama = f"http_requests_total{{path=\"{path}\"}}"
        baris.append(f"{nama} {jumlah}")
    return "\n".join(baris) + "\n"


catat_request("/produk")
catat_request("/produk")
catat_request("/checkout")

print(render_metrik(), end="")

Output yang Dihasilkan:

text
http_requests_total{path="/checkout"} 1
http_requests_total{path="/produk"} 2

Setiap baris memuat nama metrik, label (di sini path), dan nilai terkini; server Prometheus mengambil (scrape) endpoint /metrics secara berkala, menyimpan deret waktunya, lalu menghitung sinyal Rate dan Errors dari selisih antar pengambilan. Di produksi, middleware FastAPI biasanya mencatat otomatis setiap permintaan.

Alerting dan Runbook #

Data tanpa tindakan hanyalah grafik indah. Aturan praktisnya: alert pada gejala yang dirasakan pengguna (error rate tinggi, latency memburuk), bukan pada setiap penyebab (CPU 80%) — dan setiap alert yang layak membangunkan orang harus disertai runbook: dokumen singkat berisi apa yang terjadi, apa dampaknya, dan langkah pertama pemulihan. Tidak ada runbook? Alert itu sebaiknya tiket di jam kerja, bukan halaman tengah malam. Terakhir, uptime check eksternal (layanan yang mengakses https://toko.example.com/healthz dari luar) tetap diperlukan — metrik internal tidak bisa melaporkan mesin yang mati total.

Dengan health check, log terstruktur, error tracking, dan metrik, aplikasi kita tidak hanya berjalan — kesehatannya terukur, dan gangguan pertama akan kita ketahui sebelum pengguna sempat mengeluh.