mcpField
G
go-logging

go-logging

github.com/cxuu开发1861.1k 次安装19 周前更新
代码仓库

关于 go-logging

面向 Go 开发者的日志技能,介绍结构化日志、级别、上下文范围字段及敏感数据处理,适用于构建或审查生产日志,并建议新代码使用标准库 `log/slog`。

主要功能

  1. 01结构化键值日志
  2. 02选择日志级别
  3. 03上下文范围的日志字段
  4. 04排除敏感数据
  5. 05处理器配置与测试指导

适用场景

  1. 01为 Go 服务添加生产日志
  2. 02审查错误日志与返回路径
  3. 03避免在日志中记录密钥和个人数据

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cxuu/golang-skills --skill go-logging

安装后在 Claude Code 中输入/go-logging确认已加载。

附带文件references/LEVELS-AND-CONTEXT.mdreferences/LOGGING-PATTERNS.md

详细介绍

Go 日志记录

兼容性:log/slog 需要 Go 1.21+;testing/slogtest 需要 Go 1.22+。

资源路由

  • references/LEVELS-AND-CONTEXT.md - 选择日志级别、决定使用上下文中的日志记录器还是显式参数,或排除敏感字段时阅读。
  • references/LOGGING-PATTERNS.md - 配置 slog 处理器、记录 HTTP 请求、测试处理器,或从 log.Printf 迁移时阅读。

核心原则

日志是给运维人员看的,不是给开发人员看的。每条日志都应帮助 他人诊断生产问题。如果日志不能起到这个作用,那它就是噪声。


选择日志记录器

规范性:新 Go 代码应使用 log/slog。

slog 是结构化的、分级的,并且位于标准库中(Go 1.21+)。它 足以满足绝大多数生产环境的日志记录需求。

Which logger?
├─ New production code      → log/slog
├─ Trivial CLI / one-off    → log (standard)
└─ Measured perf bottleneck → zerolog or zap (benchmark first)

除非性能分析表明 slog 是热路径上的瓶颈,否则不要引入第三方日志库。 如果确实引入,请保持相同的结构化键值风格。


结构化日志记录

规范性:始终使用键值对。不要将值插入消息字符串中。

消息是对所发生事件的静态描述。动态数据应放入 键值属性中:

// 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))
键命名

建议:日志属性键使用 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)

请求范围的日志记录

建议:从上下文派生日志记录器,以携带请求范围的字段。

使用中间件为日志记录器添加请求 ID、用户 ID 或跟踪 ID,然后 通过上下文或显式参数将增强后的日志记录器传递给下游。将完整的上下文键和 中间件实现保留在日志记录模式参考文档中,以便请求范围的日志记录由一个地方统一管理。


记录日志或返回错误,二选一,不要两者兼做

只处理一次的规则属于 go-error-handling。 在日志记录工作中,应通过选择本地记录日志并恢复的路径,或附带上下文返回错误的路径来应用此规则,同一错误不要两者兼做。

例外:HTTP 处理程序和其他调用栈顶层边界可以在服务端记录详细 错误,同时向客户端返回经过清理的消息:

if err != nil {
    slog.Error("checkout failed", "err", err, "user_id", uid)
    http.Error(w, "internal error", http.StatusInternalServerError)
    return
}

有关完整的只处理一次模式和错误包装指南,请参阅 go-error-handling。


不应记录的内容

规范性:绝不要记录秘密、凭据、个人身份信息或基数高且无界的数据。

  • 密码、API 密钥、令牌、会话 ID
  • 完整信用卡号、SSN
  • 可能包含用户数据的请求/响应正文
  • 大小无界的整个切片或映射

快速参考

应做不应做
slog.Info("msg", "key", val)log.Printf("msg %v", val)
静态消息 + 结构化字段在消息中使用 fmt.Sprintf
使用 snake_case 键使用 camelCase 或不一致的键
记录日志或返回错误记录日志并返回同一个错误
从上下文派生日志记录器每次调用都创建新的日志记录器
使用带有 "err" 属性的 slog.Error对错误使用 slog.Info
在热路径上预先检查 Enabled()始终分配日志参数

相关技能

  • 错误处理:在决定记录还是返回错误,或使用一次性处理模式时,请参阅 go-error-handling
  • 上下文传播:在通过上下文传递请求范围内的值(包括日志记录器)时,请参阅 go-context
  • 性能:在优化热点路径日志记录或减少日志调用中的内存分配时,请参阅 go-performance
  • 代码审查:在审查 Go PR 中的日志记录实践时,请参阅 go-code-review

评论

支持 Markdown