Go 用 zap 搭建生产级结构化日志:字段、分级、采样与日志轮转
test12026-11-011 次阅读
标准库够用,但生产不够快
Go 标准库的 log 没有结构化字段,slog 解决了结构但默认实现偏简单。在高频服务里,zap 的零分配 JSON 编码和级别采样能明显压低日志开销。下面搭一个能直接用在生产的结构化日志。
核心:Encoder、Writer、Level 三件套
package main
import (
"os"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
func newLogger() *zap.Logger {
writer := zapcore.AddSync(&lumberjack.Logger{
Filename: "logs/app.log",
MaxSize: 100, // MB
MaxBackups: 3,
MaxAge: 7, // 天
})
cfg := zap.NewProductionEncoderConfig()
cfg.EncodeTime = zapcore.ISO8601TimeEncoder
cfg.EncodeLevel = zapcore.CapitalLevelEncoder
core := zapcore.NewCore(
zapcore.NewJSONEncoder(cfg),
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), writer),
zap.NewAtomicLevelAt(zapcore.InfoLevel),
)
return zap.New(core, zap.AddCaller())
}
带字段地记录,而不是拼字符串
结构化字段让日志可被采集系统按字段检索,而不是靠正则去抠文本。
var logger = newLogger()
defer logger.Sync()
logger.Info("request handled",
zap.String("path", "/api/users"),
zap.Int("status", 200),
zap.Duration("cost", cost),
)
// 需要格式化时再用 SugaredLogger
sugar := logger.Sugar()
sugar.Infow("order created", "order_id", 123, "amount", 99.9)
采样与级别
热点路径上同一个错误可能一秒打几千次,用 Sampler 把高频日志抽样,既保留现场又不压垮磁盘。级别用 AtomicLevel 还能运行时动态调整。
core = zapcore.NewCore(
enc,
ws,
zap.NewAtomicLevelAt(zapcore.InfoLevel),
)
// 高频 Debug 抽样:每 100 条记 1 条
sampled := zapcore.NewSamplerWithOptions(
core, true, 100, 1,
)
落地要点
- JSON 编码 + 字段,方便 ELK / Loki 检索。
- lumberjack 做按大小滚动与过期清理,别让日志把磁盘写满。
- 生产用 Info,排查时把 AtomicLevel 调到 Debug,不重启也能细看。
T
test1
文章作者
标准库够用,但生产不够快 Go 标准库的 log 没有结构化字段,slog 解决了结构但默认实现偏简单。在高频服务里,...
- 分类
- 技术
- 发布时间
- 2026-11-01
- 字数
- 约 1509 字
- 阅读
- 1 次
