go-logging

安装量: 233
排名: #8883

安装

npx skills add https://github.com/cxuu/golang-skills --skill go-logging
Go Logging
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/slog
for 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.
Read
references/LOGGING-PATTERNS.md
when setting up slog handlers, configuring JSON/text output, or migrating from log.Printf to slog.
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_case
for 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
)
,
)
Read
references/LEVELS-AND-CONTEXT.md
when optimizing log performance or pre-checking with Enabled().
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.Error
should 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
)
Read
references/LEVELS-AND-CONTEXT.md
when choosing between Warn and Error or defining custom verbosity levels.
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:
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
)
)
}
)
}
All subsequent log calls in that request carry
request_id
automatically.
Read
references/LOGGING-PATTERNS.md
when implementing logging middleware or passing loggers through context.
Log or Return, Not Both
Normative
Handle each error exactly once — either log it or return it.
Logging an error and then returning it causes duplicate noise as callers up the
stack also handle the error.
// 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
)
}
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 Read references/LEVELS-AND-CONTEXT.md when deciding what data is safe to include in log attributes. 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
返回排行榜