Frontend Labs
⋯

36. Structured logging and observability: log/slog, metrics, tracing

36.1 log/slog (standard library since Go 1.21)

logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("request handled",
	"method", r.Method,
	"path", r.URL.Path,
	"status", status,
	"latency_ms", latency.Milliseconds(),
)
// {"time":"...","level":"INFO","msg":"request handled","method":"GET",...}

Structured (key-value, machine-parseable) logs replace fmt.Printf-style free text specifically so log aggregators (Loki, Elasticsearch, CloudWatch Insights) can filter and query on fields instead of grepping strings.

36.2 Metrics: counters, gauges, histograms

import "github.com/prometheus/client_golang/prometheus"

var requestDuration = prometheus.NewHistogramVec(
	prometheus.HistogramOpts{Name: "http_request_duration_seconds"},
	[]string{"method", "path", "status"},
)

requestDuration.WithLabelValues(r.Method, r.URL.Path, status).Observe(latency.Seconds())

36.3 Tracing: propagating a request ID/span across services

Combine the context.WithValue request-ID pattern from Chapter 18 with log/slog's attribute passing, and every log line for a given request — across every service it touches — carries the same ID, turning "find every log line for this one failed request across five microservices" from a manual grep exercise into a single query.

36.4 Real-world example

The single highest-leverage observability change most young Go services are missing is: structured logs with a request ID, runtime.NumGoroutine() as a gauge (Chapter 15's war story), and net/http/pprof mounted on an internal-only port (Chapter 20) — three cheap additions that turn "why is prod slow" from a guessing game into a five-minute diagnosis.

Applied in the series: the HTTPS guide's production server logs every request with log/slog, and its SLO chapter turns request outcomes into burn-rate alerts.


Generated from real-life-golang-guide.md · 8 Oct 2026 16:36