Skip to main content
skill CX Codex

go-observability — Claude Code skill for Go logs, traces and metrics

A skill that sets conventions for Go service telemetry: structured logs with log/slog, OpenTelemetry traces and metrics, SLO alerts. Useful once a service runs in production and you need to see what it does.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add eduardo-sl/go-agent-skills --skill go-observability -a claude-code
Open on GitHub

What go-observability does

The skill covers four signals. Log lines carry key-value pairs instead of formatted sentences, and the logger arrives as a dependency rather than a package-level global. Tracing means a span per operation, ctx passed down the whole chain, and failures marked with span.RecordError plus span.SetStatus — otherwise a failed request shows up green. Metric names follow <namespace>_<subsystem>_<name>_<unit>, and labels stay narrow: a user ID or a raw request path in a label spawns a new time series for every value.

Inside are SKILL.md and four reference files loaded on demand: references/slog.md for handler setup and redaction, references/tracing.md for the tracer provider and sampling, references/metrics.md for definitions and HTTP instrumentation, references/alerting.md for RED/USE and burn-rate alerts. One section ties the signals together: a handler wrapper injects trace_id and span_id into every *Context call, and it has to override WithAttrs and WithGroup or child loggers drop them.

The Go toolchain is required, since the skill runs go and gofmt. A project rule or agent config that explicitly supersedes it wins. Profiling with pprof, error handling and health endpoints live in separate skills of the same set.

What it helps with

  • replace formatted log strings with structured key-value pairs
  • carry trace context through every call without breaking the parent span
  • decide between a histogram and a summary for a latency metric
  • alert on SLO burn rate instead of per-metric thresholds
  • keep passwords and personal data out of logs with slog.LogValuer

Example prompts for the agent

  • Add structured logging to this Go service with log/slog, injected as a dependency
  • Instrument the inbound HTTP handlers and database calls with OpenTelemetry spans
  • Add a request latency metric and suggest bucket boundaries around our SLO threshold

How to install go-observability

1Skills CLI (Vercel)

npx skills add eduardo-sl/go-agent-skills --skill go-observability -a claude-code

2Manually: put the files in place

~/.claude/skills/go-observability/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/go-observability/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about go-observability

How do I install go-observability in Claude Code?

Run npx skills add eduardo-sl/go-agent-skills --skill go-observability -a claude-code. The skill lands at ~/.claude/skills/go-observability/SKILL.md.

What does go-observability do?

It lays out how a Go service should emit structured logs, distributed traces, metrics and SLO alerts, and how to join log lines to traces with trace_id.

How is go-observability different from go-performance-review?

This one handles logging, tracing, metrics and alerting. pprof profiling, error handling and health endpoints are covered by other skills in the set.

Source text

SKILL.md · MIT
---
name: go-observability
description: >
  Structured logging, distributed tracing, metrics, and health checks for Go
  services. Covers slog, OpenTelemetry, Prometheus, and observability best
  practices. Use when: "add logging", "structured logs", "add tracing",
  "OpenTelemetry", "add metrics", "Prometheus", "observability", "instrument
  this code".
  Not for: pprof profiling (go-performance-review), error handling
  (go-error-handling), health endpoints (go-api-design).
user-invocable: true
license: MIT
compatibility: Designed for Claude Code or similar AI coding agents working on Go projects. Requires the Go toolchain.
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(gofmt:*)
metadata:
  author: eduardo-sl
  version: "1.5.1"
---

# Go Observability

Observability is not optional for production services. Every service must produce
structured logs, expose metrics, and propagate trace context. Use the stdlib
`log/slog` for logging and OpenTelemetry for tracing and metrics.

> Community default. A project skill or agent-config rule that explicitly
> supersedes `go-observability` takes precedence over this one.

Detailed reference material, loaded on demand:

- `references/slog.md` — handler setup, logger injection, child loggers,
  `LogValuer` redaction, trace-ID handler, hot paths, runtime levels.
- `references/tracing.md` — tracer provider, spans, propagation, sampling,
  profile labels, shutdown.
- `references/metrics.md` — metric definitions, HTTP instrumentation.
- `references/alerting.md` — RED/USE, histograms vs summaries, burn-rate
  alerts, alert hygiene, exemplars.

Read a reference file only when the section below is not enough.

## 1. Structured Logging with slog

Use `log/slog` (Go 1.21+) with a JSON handler in production. Every line is
key-value pairs, never a formatted sentence:

```go
// ✅ Good — structured, leveled
logger.Info("user created", slog.String("user_id", user.ID), slog.Duration("latency", elapsed))

// ❌ Bad — unparseable in production
log.Printf("user %s created in %v", user.ID, elapsed)
```

Inject the logger as a dependency; never reach for a package-level global.
Derive child loggers with `logger.With(...)` so component, method and request
ID are attached once instead of at every call site. See `references/slog.md`.

### Log levels — use them consistently

| Level | Use for |
|---|---|
| `Debug` | Verbose diagnostic info, disabled in production |
| `Info` | Normal operations: request received, job completed |
| `Warn` | Recoverable issues: retry succeeded, deprecated usage |
| `Error` | Failures requiring attention: DB down, external call failed |

NEVER log at Error level for expected conditions (user not found → Info or Warn).

### Sensitive data — NEVER log

- Passwords, tokens, API keys
- Full credit card numbers, SSNs
- Personal identifiers: email addresses, phone numbers, IP addresses
  where they identify a person
- Raw request bodies containing PII

```go
// ✅ Good — an opaque internal ID, no personal data
logger.Info("auth attempt", slog.String("user_id", userID), slog.Bool("success", ok))

// ❌ Bad — leaks a credential and a personal identifier
logger.Info("auth attempt", slog.String("password", password))
logger.Info("auth attempt", slog.String("user", email))
```

Log the stable internal ID and join to personal data in the system that is
allowed to hold it. Log retention, search access and third-party log sinks
rarely meet the bar that applies to the user table.

Make redaction a property of the type: implement `slog.LogValuer` on
secrets and on structs that hold personal data, so `slog.Any(user)` logs
only the safe fields everywhere.

### Cost and control

- Hot paths use `logger.LogAttrs` and guard expensive attributes with
  `logger.Enabled`.
- A `slog.LevelVar` in `HandlerOptions` lets the level change at run time
  without a deploy.
- `slog.NewMultiHandler` (Go 1.26+) fans out to several handlers.

## 2. Distributed Tracing with OpenTelemetry

Start a span for every operation worth seeing on a waterfall — inbound
requests, DB calls, outbound HTTP, meaningful business steps — and always
`defer span.End()`.

Rules the reference examples follow:

- Name the span after the operation (`GetUser`, `db.query`), never after the
  fully-qualified function, and never `doStuff`.
- On failure call `span.RecordError(err)` and `span.SetStatus(codes.Error, ...)`,
  or the trace shows a green span for a failed request.
- Pass `ctx` down the whole chain. A `context.Background()` mid-chain silently
  starts a new trace and breaks the parent link.
- Sample with `ParentBased(TraceIDRatioBased(r))` so services agree on a
  trace; keep errors and slow requests with tail sampling in the collector.
- Profiles are the fourth signal: continuous profiling in production, with
  bounded `pprof.Labels` (route, tenant tier) to split a hot function.

Setup and examples in `references/tracing.md`.

## 3. Metrics with OpenTelemetry / Prometheus

| Type | Use for | Example |
|---|---|---|
| Counter | Monotonically increasing values | Requests total, errors total |
| Gauge | Values that go up and down | Active connections, queue depth |
| Histogram | Distribution of values | Request latency, response size |

Naming is `<namespace>_<subsystem>_<name>_<unit>`:

```text
http_request_duration_seconds     ✅ (unit in name)
http_requests_total               ✅ (counter with _total suffix)
db_connections_active             ✅ (gauge, no suffix needed)
user_signups                      ❌ (missing _total for counter)
requestLatency                    ❌ (camelCase, no unit)
```

Keep cardinality bounded. Label with the route pattern, method and status —
never a user ID, request ID or raw `r.URL.Path`, each of which mints a new
time series per value and eventually takes the metrics backend down.

Definitions and middleware in `references/metrics.md`.

## 4. Connecting Logs, Traces, and Metrics

A log line without a trace ID cannot be joined to the request that produced
it. Wrap the handler once so every `*Context` log call adds `trace_id` and
`span_id` from `ctx` — the wrapper must also override `WithAttrs` and
`WithGroup`, or child loggers lose it. Attach exemplars (trace IDs) to
latency histograms to jump from a p99 spike to an offending trace.

## 5. Alerting and SLOs

- Measure RED (rate, errors, duration) per route for services and USE
  (utilization, saturation, errors) for pools and queues.
- Latency is a **Histogram**, never a Summary — summary quantiles cannot be
  aggregated across instances. Put buckets around the SLO threshold.
- Page on SLO **burn rate** over a long and a short window together; send
  slower burns to a ticket.
- Alert on symptoms, not causes; `rate()` not `irate()`; `absent()` for
  series that must exist; a runbook link on every page.

Queries and exemplar wiring: `references/alerting.md`.

## 6. Graceful Shutdown of Telemetry

The batch span processor holds spans in memory. Call `tp.Shutdown(ctx)` with
its own timeout on the way out, or the last seconds before a crash — the
interesting ones — never reach the collector.

Both examples in `references/tracing.md`.

## Verification Checklist

1. All logging uses `log/slog` with structured key-value pairs, not `fmt.Printf` or `log.Printf`
2. Logger is injected as a dependency, not used as a global
3. No sensitive data (passwords, tokens, PII) in log output
4. Trace context is propagated through all function calls via `context.Context`
5. Spans are created for significant operations (DB calls, HTTP requests, business logic)
6. Spans record errors with `span.RecordError(err)` and set error status
7. Metrics follow naming conventions: `_seconds`, `_total`, `_bytes`
8. No high-cardinality labels (user IDs, request IDs) in metrics
9. Telemetry providers are shut down gracefully on service exit
10. Trace IDs are included in log entries for correlation
11. Latency recorded as histograms; paging alerts are SLO burn-rate alerts with runbooks

© eduardo-sl · MIT · eduardo-sl/go-agent-skills

Similar skills

All skills for Backend and APIs →

From the same set11

go-semantic-tools Finds function calls, interface implementations, and dependency graphs in Go via gopls and go list, not text search. Understands implicit interfaces, embedding, and cross-package dependencies that grep misses. CX Codex +1 ★ 83repo stars go-ci A skill that helps your AI agent write and set up GitHub Actions for Go projects. Use it when you need a pipeline with linting, tests, security checks, and caching. CX Codex +1 ★ 83repo stars git-commit A skill that makes your agent write commit messages in Conventional Commits style: typed, scoped, imperative. Useful when the repo history has turned into noise. CX Codex +1 ★ 83repo stars go-troubleshooting A skill that walks the agent through Go runtime diagnosis: panics, deadlocks, goroutine and memory leaks, race reports. Useful when a program crashes or hangs and the cause is unclear. CX Codex +1 ★ 83repo stars go-error-handling A skill that tells your agent how to create, wrap and inspect Go errors: %w wrapping, sentinel errors, custom types, errors.Is and errors.As. CX Codex +1 ★ 83repo stars go-context A skill that makes your coding agent handle context.Context in Go correctly: cancellation, timeouts, values and the usual anti-patterns. CX Codex +1 ★ 83repo stars go-project-layout Picks a folder layout for a new Go project: cmd/, internal/, or a flat root for small tools. Useful at the start, before the structure hardens. CX Codex +1 ★ 83repo stars go-grpc A skill that steers your coding agent through gRPC work in Go: proto contracts, error codes, deadlines, interceptors and streaming. CX Codex +1 ★ 83repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor