其他
Go 新代码选择日志方案、配置 slog…
为 Go 代码选择 logger、配置 `slog`、编写结构化日志语句、决定日志级别或从 `log.Printf` 迁移时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
Go 新代码选择日志方案、配置 slog通用
解决思路
- 把日志写给运维而非开发者:每一行日志都应能帮助诊断生产问题;若不能,就是噪音。
- 新生产代码使用 `log/slog`;简单 CLI 或一次性脚本用标准 `log`;只有实测性能瓶颈才考虑 `zerolog` 或 `zap`,且先 benchmark。
- 除非 profiling 证明 `slog` 在热路径是瓶颈,否则不要引入第三方日志库;若引入,保持相同的结构化 key-value 风格。
- 始终使用 key-value 对,绝不在消息字符串中插值;消息是静态描述,动态数据放入属性。例如使用 `slog.Info` 传入静态消息和 `"order_id", orderID, "total", total`,而不是 `slog.Info(fmt.Sprintf(...))`。
- 日志属性键使用 `snake_case`:小写、下划线分隔、跨代码库一致,如 `user_id`、`request_id`、`elapsed_ms`。
- 性能关键路径使用类型化构造器避免分配:`slog.LogAttrs(ctx, slog.LevelInfo, "request handled", slog.String("method", r.Method), slog.Int("status", code), slog.Duration("elapsed", elapsed))`。
- 按语义选择日志级别:Debug 用于开发者诊断和跟踪内部状态,生产默认禁用;Info 用于显著生命周期事件(启动、关闭、配置加载),生产启用;Warn 用于意外但可恢复的情况(使用已弃用功能、重试成功),生产启用;Error 用于操作失败且需要运维关注,生产启用。
- 应用级别经验规则:没人需要行动的不记 Error,改用 Warn 或 Info;只有附加调试器才有用的记 Debug;`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)`。
- 请求作用域日志:用 middleware 给 logger 增加 request ID、user ID 或 trace ID,然后通过 context 或显式参数把增强后的 logger 传给下游。
- 把完整 context-key 和 middleware 实现放在 logging patterns 参考中,使请求作用域日志只有一个拥有者。
- 对同一错误,选择本地 log-and-recover 路径,或带回上下文的 return 路径,不要两者都做。
- 例外:HTTP handler 等栈顶边界可以在服务端记录详细错误,同时向客户端返回脱敏消息,如 `slog.Error("checkout failed", "err", err, "user_id", uid)` 并 `http.Error(w, "internal error", http.StatusInternalServerError)`。
- 绝不记录秘密、凭证、PII 或无界高基数数据:密码、API 密钥、令牌、会话 ID;完整信用卡号、SSN;可能包含用户数据的请求/响应体;无界大小的整个 slice 或 map。
- 用 `slog.Info("msg", "key", val)` 替代 `log.Printf("msg %v", val)`。
- 用静态消息加结构化字段,替代在消息中使用 `fmt.Sprintf`。
- 用 `snake_case` 键,替代 camelCase 或不一致键。
- 记录或返回错误,不要记录并返回同一错误。
- 从 context 派生 logger,不要每次调用创建新 logger。
- 用带 `err` 属性的 `slog.Error`,不要用 `slog.Info` 记录错误。
- 在热路径上预检查 `Enabled()`,不要总是分配日志参数。
- 资源路由:选择日志级别、决定 logger-in-context 还是显式参数、排除敏感字段时,读 `references/LEVELS-AND-CONTEXT.md`;配置 slog handler、记录 HTTP 请求、测试 handler、从 `log.Printf` 迁移时,读 `references/LOGGING-PATTERNS.md`。
- 相关技能:决定记录还是返回错误、使用 handle-once 模式时见 `go-error-handling`;通过 context 传递请求作用域值(包括 logger)时见 `go-context`;优化热路径日志或减少日志调用分配时见 `go-performance`;在 Go PR 中审查日志实践时见 `go-code-review`。
适用边界 · 注意事项
- 不覆盖错误处理策略:需要决定错误处理、错误包装或 handle-once 模式时,改用 `go-error-handling`。
- 不适用于 Go 1.21 以下的代码(`log/slog` 不可用);`testing/slogtest` 需要 Go 1.22+。
- 除非 profiling 显示 `slog` 是热路径瓶颈,否则不要引入 `zerolog`、`zap` 等第三方日志库。