Episode ini membuat aplikasi terlihat: metrics Prometheus sebagai middleware, tracing dengan OpenTelemetry, dan structured logs dengan slog. Kalian juga memakai middleware.Heartbeat untuk health check serta menyusun dashboard dan alerting untuk latency, error rate, dan throughput.

Aplikasi yang berjalan tanpa penglihatan adalah aplikasi yang tidak bisa dioperasikan. Episode 18 menghubungkan router chi ke tiga pilar observability: metrics, traces, dan logs. Ketiganya memberi jawaban atas pertanyaan yang selalu muncul di produksi — lambat di mana, error berapa banyak, dan request berapa tinggi. Karena chi murni net/http, seluruh ekosistem observability Go menempel tanpa adaptor. Kita mulai dari Prometheus, lalu OpenTelemetry, dan menutup dengan health check.
Ekspos metrik HTTP melalui middleware:
go get github.com/prometheus/client_golang/prometheus/promhttpfunc prometheusMetrics(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
start := time.Now()
next.ServeHTTP(w, req)
httpDuration.WithLabelValues(
req.URL.Path, req.Method,
).Observe(time.Since(start).Seconds())
})
}httpDuration.WithLabelValues(path, method).Observe(...) mencatat durasi per rute dan method. Histogram ini menjadi dasar perhitungan latency percentiles di dashboard.
r := chi.NewRouter()
r.Use(prometheusMetrics)
r.Get("/metrics", func(w http.ResponseWriter, req *http.Request) {
promhttp.Handler().ServeHTTP(w, req)
})promhttp.Handler().ServeHTTP(w, req) melayani output Prometheus pada path /metrics. Pastikan endpoint ini dilindungi atau hanya dapat diakses internal.
scrape_configs:
- job_name: chi-service
static_configs:
- targets: ["localhost:8080"]targets: ["localhost:8080"] memberitahu Prometheus untuk menarik metrik dari aplikasi setiap interval scrape.
OpenTelemetry menangkap jejak request antar service:
go get go.opentelemetry.io/otelfunc otelMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
ctx, span := tracer.Start(req.Context(),
req.Method+" "+req.URL.Path)
defer span.End()
span.SetAttributes(
attribute.String("http.method", req.Method),
attribute.String("http.target", req.URL.Path),
)
next.ServeHTTP(w, req.WithContext(ctx))
})
}tracer.Start(req.Context(), name) membuka span baru untuk setiap request. Span membawa method dan path sebagai atribut — menghubungkan latensi ke penyebabnya. Saat request diteruskan ke service lain, header propagasi dibawa oleh http.Client, sehingga jejak lintas service tersambung dalam satu trace tree di backend seperti Jaeger atau Tempo.
Kombinasikan slog dengan metrik untuk konteks lengkap:
func requestLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
start := time.Now()
next.ServeHTTP(w, req)
slog.Info("http_request",
"method", req.Method,
"path", req.URL.Path,
"latency", time.Since(start).Milliseconds(),
)
})
}slog.Info("http_request", "method", req.Method, "latency", ...) menulis satu baris JSON per request. Latency dalam milidetik siap dikirim ke agregator log seperti Loki. Tambahkan trace ID sebagai atribut ("trace_id", traceID) agar log dan span OpenTelemetry terbaca dalam satu utas pencarian saat request bermasalah.
r.Use(middleware.Heartbeat("/healthz"))middleware.Heartbeat("/healthz") membalas OK dengan status 200 pada path /healthz tanpa melibatkan handler lain. Probes Kubernetes dan load balancer memakai endpoint ini untuk memutuskan kapan request dikirim.
/healthz): server hidup? Bila gagal, pod di-restart./readyz): siap menerima traffic? Bila gagal, traffic dihentikan sementara.Untuk readiness, tambahkan cek dependency seperti database dengan pool.Ping(req.Context()) — server tidak dianggap siap sampai koneksi database sehat, dan load balancer tidak akan mengirim traffic saat dependency bermasalah.
Tiga metrik utama yang selalu dipantau:
groups:
- name: chi-alerts
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{code=~"5.."}[5m]) > 0.05
labels:
severity: critical
annotations:
summary: "Error rate melebihi 5 persen"rate(http_requests_total{code=~"5.."}[5m]) > 0.05 memicu alert saat error 5xx melebihi 5 persen selama 5 menit. Dashboard Grafana menampilkan tren latency dan throughput dari metrik yang sama.
Inti yang harus dibawa pulang:
/metrics dilayani dengan promhttp.middleware.Heartbeat menyediakan health check instan.Di episode 19 selanjutnya kita memoles performa: performance dan troubleshooting — pola rute yang efisien, tuning http.Server, connection pooling, caching dengan Redis, serta solusi masalah umum seperti route conflict, panic handler, deadlock context, dan kebocoran goroutine.