Go
Summary - Observability
Combine slog and metrics to write an observability layer.
Observability summary
Three pillars: logs (what happened? — slog), metrics (how much, how often? — counter/gauge/histogram) and traces (where did it slow down? — spans). OpenTelemetry unifies all three in one standard. On top of these, /livez and /readyz let the orchestrator manage the service correctly.
Correlating logs with the trace ID (adding trace_id to log lines) makes moving between the three pillars easy.
Request ID middleware
Giving every request an ID and putting it in both the response header and the logs makes it easy to find an error a user reports:
func istekID(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := r.Header.Get("X-Request-ID")
if id == "" { id = yeniID() }
w.Header().Set("X-Request-ID", id)
log := slog.With("istek_id", id)
log.Info("istek", "yol", r.URL.Path)
next.ServeHTTP(w, r)
})
}
Exercise Request ID
Write istekID(next http.Handler) http.Handler: copy the incoming X-Request-ID header to the response header, using "yeni" if it is empty. Send a request without the header and print the response's X-Request-ID.
Show example solution
package main
import (
"fmt"
"net/http"
"net/http/httptest"
)
func istekID(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := r.Header.Get("X-Request-ID")
if id == "" {
id = "yeni"
}
w.Header().Set("X-Request-ID", id)
next.ServeHTTP(w, r)
})
}
func main() {
h := istekID(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
fmt.Println(rec.Header().Get("X-Request-ID"))
}
Test yourself
-
Which answers "did the error rate rise in the last hour?" fastest?
- Metrics
- A single trace
- pprof
- The source code
Show answer
Metrics — Rates and trends are what metrics are for; to find why it rose you then drill into the related traces and logs.
-
Structured log
slog.____("ödeme başarısız", "hata", err, "tutar", 120)
Show answer
slog.Error("ödeme başarısız", "hata", err, "tutar", 120)
-
Pillar and question
- Log
- What happened?
- Metrik
- How much?
- Trace
- Where is it slow?
- /readyz
- Can it take traffic?
Next lesson: Challenge 1 - Reflection