Go Observability (OpenTelemetry + Prometheus + slog)
Observability in Go rests on three pillars: traces (request flow), metrics (counters/gauges/histograms), and logs (structured events). Correlate them with Trace ID, Span ID, and Request ID.
When to Use This Skill
- Adding or fixing observability in Go microservices
- Setting up distributed tracing (OpenTelemetry) across services
- Exposing Prometheus metrics and /metrics endpoint
- Using slog for structured, trace-correlated logging
- Implementing health checks (liveness/readiness) and graceful shutdown
- Debugging production issues with traces and metrics
Core Principles
- Traces: Request flow across services; use context propagation.
- Metrics: Counters, gauges, histograms; keep label cardinality bounded.
- Logs: slog (Go 1.21+) with trace_id/span_id for correlation.
All three should share Trace ID (and optionally Request ID) so logs and metrics can be tied to spans.
Quick Start
- Tracer: Initialize OTel tracer provider with OTLP or Jaeger exporter; set as global provider; defer
tp.Shutdown(ctx).
- Spans:
ctx, span := otel.Tracer("svc").Start(ctx, "op"); defer span.End(); pass ctx through the call chain.
- HTTP: Use
otelhttp.NewHandler(handler, "route-name") for auto-instrumentation.
- Metrics: Register Prometheus counters/histograms; expose
/metrics with promhttp.Handler().
- Logs: Use
slog with slog.With("trace_id", traceID); include trace_id in log attributes.
- Health: Implement
/health (liveness) and /ready (readiness); call tp.Shutdown on SIGTERM.
Quick Reference
// Init tracer
tp, _ := initTracer("service-name")
defer tp.Shutdown(context.Background())
// Span
ctx, span := otel.Tracer("name").Start(ctx, "operation")
defer span.End()
span.SetAttributes(attribute.String("key", "value"))
// Metrics
counter := promauto.NewCounterVec(opts, []string{"label"})
histogram := promauto.NewHistogramVec(opts, []string{"label"})
// Logging
logger := slog.With("trace_id", traceID)
logger.Info("message", "key", value)
// Health
http.HandleFunc("/health", livenessHandler)
http.HandleFunc("/ready", readinessHandler)
Additional Resources
Source: Marz32onE/otel-traces-test — distributed by TomeVault.
1---2name: golang-o11y3description: Instruments Go services with OpenTelemetry tracing, Prometheus metrics, and slog structured logging. Use when adding or debugging observability in Go microservices, setting up distributed tracing, metrics endpoints, or correlating logs with traces. Use when this capability is needed.4---56# Go Observability (OpenTelemetry + Prometheus + slog)78Observability in Go rests on three pillars: **traces** (request flow), **metrics** (counters/gauges/histograms), and **logs** (structured events). Correlate them with Trace ID, Span ID, and Request ID.910## When to Use This Skill1112- Adding or fixing observability in Go microservices13- Setting up distributed tracing (OpenTelemetry) across services14- Exposing Prometheus metrics and /metrics endpoint15- Using slog for structured, trace-correlated logging16- Implementing health checks (liveness/readiness) and graceful shutdown17- Debugging production issues with traces and metrics1819## Core Principles2021- **Traces**: Request flow across services; use context propagation.22- **Metrics**: Counters, gauges, histograms; keep label cardinality bounded.23- **Logs**: slog (Go 1.21+) with trace_id/span_id for correlation.2425All three should share Trace ID (and optionally Request ID) so logs and metrics can be tied to spans.2627## Quick Start28291. **Tracer**: Initialize OTel tracer provider with OTLP or Jaeger exporter; set as global provider; defer `tp.Shutdown(ctx)`.302. **Spans**: `ctx, span := otel.Tracer("svc").Start(ctx, "op"); defer span.End();` pass `ctx` through the call chain.313. **HTTP**: Use `otelhttp.NewHandler(handler, "route-name")` for auto-instrumentation.324. **Metrics**: Register Prometheus counters/histograms; expose `/metrics` with `promhttp.Handler()`.335. **Logs**: Use `slog` with `slog.With("trace_id", traceID)`; include trace_id in log attributes.346. **Health**: Implement `/health` (liveness) and `/ready` (readiness); call `tp.Shutdown` on SIGTERM.3536## Quick Reference3738```go39// Init tracer40tp, _ := initTracer("service-name")41defer tp.Shutdown(context.Background())4243// Span44ctx, span := otel.Tracer("name").Start(ctx, "operation")45defer span.End()46span.SetAttributes(attribute.String("key", "value"))4748// Metrics49counter := promauto.NewCounterVec(opts, []string{"label"})50histogram := promauto.NewHistogramVec(opts, []string{"label"})5152// Logging53logger := slog.With("trace_id", traceID)54logger.Info("message", "key", value)5556// Health57http.HandleFunc("/health", livenessHandler)58http.HandleFunc("/ready", readinessHandler)59```6061## Additional Resources6263- **Full reference**: Setup, code examples, decision trees (OTel vs Prometheus vs slog), anti-patterns, metric naming — see [reference.md](reference.md).64- **Official**: [OpenTelemetry Go](https://opentelemetry.io/docs/instrumentation/go/), [Prometheus client_golang](https://github.com/prometheus/client_golang), [log/slog](https://pkg.go.dev/log/slog).6566---67> Source: [Marz32onE/otel-traces-test](https://github.com/Marz32onE/otel-traces-test) — distributed by [TomeVault](https://tomevault.io).68<!-- tomevault:4.0:skill_md:2026-06-16 -->