go-logging
Use when choosing a logging approach, configuring slog, writing structured log statements, or deciding log levels in Go. Also use when setting up production logging, adding request-scoped context to logs, or migrating from log to slog, even if the user doesn't explicitly mention logging. Does not cover error handling strategy (see go-error-handling).
How do I install this agent skill?
npx skills add https://github.com/cxuu/golang-skills --skill go-loggingIs this agent skill safe to install?
- Gen Agent Trust Hubpass
This skill provides comprehensive documentation and best practices for structured logging in Go using the standard library's log/slog package. It covers logging levels, context propagation, performance optimizations, and handler implementation.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
- Runlayerpass
3 files scanned · No issues
- ZeroLeakspass
Score: 93/100 · 2 sections analyzed
What does this agent skill do?
Go Logging
Compatibility:
log/slogrequires Go 1.21+;testing/slogtestrequires Go 1.22+.
Resource Routing
references/LEVELS-AND-CONTEXT.md- Read when choosing log levels, deciding logger-in-context versus explicit parameters, or excluding sensitive fields.references/LOGGING-PATTERNS.md- Read when configuring slog handlers, logging HTTP requests, testing handlers, or migrating fromlog.Printf.
Core Principle
Logs are for operators, not developers. Every log line should help someone diagnose a production issue. If it doesn't serve that purpose, it's noise.
Choosing a Logger
Normative: Use
log/slogfor new Go code.
slog is structured, leveled, and in the standard library (Go 1.21+). It
covers the vast majority of production logging needs.
Which logger?
├─ New production code → log/slog
├─ Trivial CLI / one-off → log (standard)
└─ Measured perf bottleneck → zerolog or zap (benchmark first)
Do not introduce a third-party logging library unless profiling shows slog
is a bottleneck in your hot path. When you do, keep the same structured
key-value style.
Structured Logging
Normative: Always use key-value pairs. Never interpolate values into the message string.
The message is a static description of what happened. Dynamic data goes in key-value attributes:
// Good: static message, structured fields
slog.Info("order placed", "order_id", orderID, "total", total)
// Bad: dynamic data baked into the message string
slog.Info(fmt.Sprintf("order %d placed for $%.2f", orderID, total))
Key Naming
Advisory: Use
snake_casefor log attribute keys.
Keys should be lowercase, underscore-separated, and consistent across the
codebase: user_id, request_id, elapsed_ms.
Typed Attributes
For performance-critical paths, use typed constructors to avoid allocations:
slog.LogAttrs(ctx, slog.LevelInfo, "request handled",
slog.String("method", r.Method),
slog.Int("status", code),
slog.Duration("elapsed", elapsed),
)
Log Levels
Advisory: Follow these level semantics consistently.
| Level | When to use | Production default |
|---|---|---|
| Debug | Developer-only diagnostics, tracing internal state | Disabled |
| Info | Notable lifecycle events: startup, shutdown, config loaded | Enabled |
| Warn | Unexpected but recoverable: deprecated feature used, retry succeeded | Enabled |
| Error | Operation failed, requires operator attention | Enabled |
Rules of thumb:
- If nobody should act on it, it's not Error — use Warn or Info
- If it's only useful with a debugger attached, it's Debug
slog.Errorshould always include an"err"attribute
slog.Error("payment failed", "err", err, "order_id", id)
slog.Warn("retry succeeded", "attempt", n, "endpoint", url)
slog.Info("server started", "addr", addr)
slog.Debug("cache lookup", "key", key, "hit", hit)
Request-Scoped Logging
Advisory: Derive loggers from context to carry request-scoped fields.
Use middleware to enrich a logger with request ID, user ID, or trace ID, then pass the enriched logger downstream via context or as an explicit parameter. Keep the full context-key and middleware implementation in the logging patterns reference so request-scoped logging has one owner.
Log or Return, Not Both
The handle-once rule belongs to go-error-handling. In logging work, apply it by choosing either a local log-and-recover path or a return path with context, not both for the same error.
Exception: HTTP handlers and other top-of-stack boundaries may log detailed errors server-side while returning a sanitized message to the client:
if err != nil {
slog.Error("checkout failed", "err", err, "user_id", uid)
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
See go-error-handling for the full handle-once pattern and error wrapping guidance.
What NOT to Log
Normative: Never log secrets, credentials, PII, or high-cardinality unbounded data.
- Passwords, API keys, tokens, session IDs
- Full credit card numbers, SSNs
- Request/response bodies that may contain user data
- Entire slices or maps of unbounded size
Quick Reference
| Do | Don't |
|---|---|
slog.Info("msg", "key", val) | log.Printf("msg %v", val) |
| Static message + structured fields | fmt.Sprintf in message |
snake_case keys | camelCase or inconsistent keys |
| Log OR return errors | Log AND return the same error |
| Derive logger from context | Create a new logger per call |
Use slog.Error with "err" attr | slog.Info for errors |
Pre-check Enabled() on hot paths | Always allocate log args |
Related Skills
- Error handling: See go-error-handling when deciding whether to log or return an error, or for the handle-once pattern
- Context propagation: See go-context when passing request-scoped values (including loggers) through context
- Performance: See go-performance when optimizing hot-path logging or reducing allocations in log calls
- Code review: See go-code-review when reviewing logging practices in Go PRs
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/cxuu/golang-skills/go-logging">View go-logging on skillZs</a>