日志
日志
Zap 是 Uber 开源的高性能结构化日志库,支持日志分级、JSON 输出、强类型字段和自定义编码器。
go get go.uber.org/zap
Zap 提供两种日志器:
| 类型 | 特点 | 适用场景 |
|---|---|---|
Logger | 使用强类型字段,分配更少、性能更高 | 生产环境和高频日志 |
SugaredLogger | 支持键值对和 printf 风格 API,使用更方便 | 业务代码和低频日志 |
Logger
zap.NewProduction 默认输出 JSON,适合由日志系统采集和检索。
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("request completed",
zap.String("method", "GET"),
zap.String("path", "/users/1"),
zap.Int("status", 200),
zap.Duration("latency", 35*time.Millisecond),
)
字段会作为独立属性写入 JSON,比把所有信息拼接到消息字符串中更容易查询。
SugaredLogger
Sugar 将 Logger 转换为语法更灵活的 SugaredLogger。
sugar := logger.Sugar()
sugar.Infow("request completed",
"method", "GET",
"path", "/users/1",
"status", 200,
)
sugar.Infof("user %d logged in", 1)
Infow 的键值参数应成对出现,键应使用字符串。需要更好的类型安全和性能时,优先使用 Logger。
日志级别
Zap 提供 Debug、Info、Warn、Error、DPanic、Panic 和 Fatal 等级别。
logger.Debug("cache missed", zap.String("key", "user:1"))
logger.Info("server started", zap.Int("port", 8080))
logger.Warn("retrying request", zap.Int("attempt", 2))
logger.Error("query failed", zap.Error(err))
Panic 会在写入日志后触发 panic,Fatal 会在写入日志后调用 os.Exit(1),常规错误处理不应使用它们。
子日志器
With 可以创建带有固定上下文的子日志器,避免在每条日志中重复传入字段。
requestLogger := logger.With(
zap.String("request_id", "req-123"),
zap.Int64("user_id", 1),
)
requestLogger.Info("request started")
requestLogger.Info("request completed", zap.Int("status", 200))
开发与生产配置
devLogger, _ := zap.NewDevelopment() // 易读的控制台输出,默认开启 Debug
prodLogger, _ := zap.NewProduction() // JSON 输出,默认从 Info 开始
需要调整级别、时间格式或输出位置时,可以修改 zap.Config 后再构建日志器:
config := zap.NewProductionConfig()
config.Level = zap.NewAtomicLevelAt(zap.WarnLevel)
config.OutputPaths = []string{"stdout", "./app.log"}
config.EncoderConfig.TimeKey = "time"
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
logger, _ := config.Build()
defer logger.Sync()
实践建议
- 生产环境使用 JSON 输出,并使用稳定的字段名。
- 传递
error时使用zap.Error(err),不要只记录err.Error()。 - 在请求入口创建带
request_id的子日志器,再向下传递。 - 程序退出前调用
Sync刷新缓冲区;不要在每次记录后调用。 - 日志中不应记录密码、Token 或完整的个人敏感信息。