Go 日志
Go 标准库与第三方日志方案,涵盖 slog 结构化日志、日志级别、上下文集成与生产环境最佳实践。
#type / concept
#status / growing
#tech / dev
#resource / go
[!info] related notes
- 所属 MOC: Go 服务工程
- 前置概念: Go Context
- 并列概念: Go 配置管理, Go 认证与 JWT
Go 日志
一句话定义
Go 日志是从标准库 log 到 log/slog(Go 1.21+)再到第三方库的演进路径,核心目标是在服务中输出结构化、可查询、可关联的日志。
核心机制 / 工作原理
标准库 log 的局限:仅支持非结构化的纯文本输出,无日志级别,无键值对字段,每次输出自动加时间戳但格式固定。适合脚本和工具,不适合生产服务。
log/slog(Go 1.21+):
- Handler 接口:
slog.Handler定义了日志输出的抽象层。TextHandler输出人类可读文本,JSONHandler输出机器可解析 JSON。 - 日志级别:
Debug < Info < Warn < Error,通过slog.LevelVar可运行时动态调整。 - 结构化字段:
slog.String("key", "value")、slog.Int("count", 42)等类型安全的属性。 - Context 集成:
slog.With()创建带固定字段的 Logger,slog.WithGroup()组织字段命名空间。
// 创建 JSON Handler,设置最低级别为 Info
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
})
logger := slog.New(handler)
// 结构化日志输出
logger.Info("user login",
slog.String("user_id", "u-123"),
slog.String("ip", "10.0.0.1"),
slog.Duration("latency", 42*time.Millisecond),
)
// 带 Context 的 Logger(可注入 trace ID)
logger = logger.With(slog.String("trace_id", "abc-123"))
logger.Info("order created", slog.String("order_id", "o-456"))
第三方库:
- zerolog:零分配设计,极致性能。链式 API:
log.Info().Str("key", "val").Msg("done")。 - zap:Uber 开源,高性能结构化日志。
zap.Logger和zap.SugaredLogger两种模式。
最小例子 / 最小场景
package main
import (
"context"
"log/slog"
"os"
)
func main() {
// 生产环境推荐 JSON 输出
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
})
slog.SetDefault(slog.New(handler))
ctx := context.Background()
slog.InfoContext(ctx, "server starting",
slog.Int("port", 8080),
slog.String("env", "production"),
)
}
// 输出: {"time":"2026-06-25T10:00:00Z","level":"INFO","msg":"server starting","port":8080,"env":"production"}
为什么重要
- 可观测性基础:日志是排查线上问题的第一道防线,结构化日志可被 ELK、Loki 等系统高效索引和查询。
- 日志关联:通过 trace_id 将同一请求链路的日志串联,是分布式追踪的关键环节。
- 性能影响:非结构化日志在高 QPS 下成为瓶颈;slog/zerolog 的零分配设计避免 GC 压力。
- 运维需求:动态日志级别允许在不重启服务的情况下临时开启 Debug 日志排查问题。
边界与易混淆点
logvsslog:log是全局单例、无级别、无结构;slog是标准库的现代化替代,但 Go 1.21 才引入。旧项目迁移需逐步替换。- Logger 注入方式:推荐通过
context.Context传递 Logger(slog.With()返回新实例),而非使用全局变量,便于测试和请求级字段关联。 - zerolog vs zap vs slog:slog 是标准库,无额外依赖;zerolog 性能最佳但 API 风格不同;zap 功能最全但依赖较重。新项目优先 slog。
- 日志级别不是越多越好:Debug/Info/Warn/Error 四级足够。Trace 和 Fatal 往往被滥用——Fatal 会
os.Exit(1)跳过 defer 清理。 - 敏感信息:密码、token、PII 永远不要写入日志。使用脱敏函数或在 Handler 层统一过滤。