Loading...
Loading...
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).
npx skill4agent add cxuu/golang-skills go-loggingNormative: Usefor new Go code.log/slog
slogWhich logger?
├─ New production code → log/slog
├─ Trivial CLI / one-off → log (standard)
└─ Measured perf bottleneck → zerolog or zap (benchmark first)slogRead references/LOGGING-PATTERNS.md when setting up slog handlers, configuring JSON/text output, or migrating from log.Printf to slog.
Normative: Always use key-value pairs. Never interpolate values into the message string.
// 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))Advisory: Usefor log attribute keys.snake_case
user_idrequest_idelapsed_msslog.LogAttrs(ctx, slog.LevelInfo, "request handled",
slog.String("method", r.Method),
slog.Int("status", code),
slog.Duration("elapsed", elapsed),
)Read references/LEVELS-AND-CONTEXT.md when optimizing log performance or pre-checking with Enabled().
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 |
slog.Error"err"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)Read references/LEVELS-AND-CONTEXT.md when choosing between Warn and Error or defining custom verbosity levels.
Advisory: Derive loggers from context to carry request-scoped fields.
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logger := slog.With("request_id", requestID(r))
ctx := context.WithValue(r.Context(), loggerKey, logger)
next.ServeHTTP(w, r.WithContext(ctx))
})
}request_idRead references/LOGGING-PATTERNS.md when implementing logging middleware or passing loggers through context.
Normative: Handle each error exactly once — either log it or return it.
// Bad: logged here AND by every caller up the stack
if err != nil {
slog.Error("query failed", "err", err)
return fmt.Errorf("query: %w", err)
}
// Good: wrap and return — let the caller decide
if err != nil {
return fmt.Errorf("query: %w", err)
}if err != nil {
slog.Error("checkout failed", "err", err, "user_id", uid)
http.Error(w, "internal error", http.StatusInternalServerError)
return
}Normative: Never log secrets, credentials, PII, or high-cardinality unbounded data.
Read references/LEVELS-AND-CONTEXT.md when deciding what data is safe to include in log attributes.
| Do | Don't |
|---|---|
| |
| Static message + structured fields | |
| 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 | |
Pre-check | Always allocate log args |