1 介绍
1.1 简介
01.高性能日志库
Uber开源、结构化日志、零分配、高性能
02.核心特性
快速、结构化、分级、可配置、生产就绪
03.设计理念
性能优先、类型安全、灵活配置、易于使用
04.应用场景
高并发服务、微服务、性能敏感、生产环境
1.2 核心特性
01.高性能
零分配、对象池、快速序列化、基准测试领先
02.结构化日志
键值对、类型安全、易于解析、查询友好
03.分级日志
Debug、Info、Warn、Error、DPanic、Panic、Fatal
04.灵活配置
Encoder、Core、Sampler、Hook、可扩展
1.3 与其他日志库对比
01.vs logrus
Zap更快、类型安全、logrus易用、生态丰富
02.vs zerolog
性能相当、Zap功能更全、zerolog更简洁
03.vs标准库log
Zap性能远超、功能丰富、结构化、生产级
04.选择建议
性能优先Zap、简单场景标准库、易用logrus
1.4 使用场景
01.高并发服务
Web服务、API网关、微服务、性能要求高
02.生产环境
日志收集、监控告警、问题排查、审计
03.性能敏感
热路径、高频日志、低延迟、资源受限
04.结构化日志
日志分析、查询检索、数据挖掘、可视化
1.5 快速开始
01.安装
a.安装命令
go get -u go.uber.org/zap
02.预设Logger
a.快速使用
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("hello zap")
03.基础使用
a.结构化日志
logger.Info("user login",
zap.String("username", "alice"),
zap.Int("age", 25),
)
04.Sugar Logger
a.Printf风格
sugar := logger.Sugar()
sugar.Infof("user %s login, age: %d", "alice", 25)
2 Logger配置
2.1 汇总:5个
01.预设Logger
Production、Development、Example、快速开始
02.自定义Logger
Config、Core、Encoder、自定义配置
03.日志级别
Debug到Fatal、动态级别、级别过滤
04.输出配置
Stdout、文件、多输出、同步异步
05.编码器
JSON、Console、自定义、格式化
2.2 预设Logger
01.Production
a.生产环境
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("production logger", zap.String("env", "prod"))
02.Development
a.开发环境
logger, _ := zap.NewDevelopment()
defer logger.Sync()
logger.Debug("debug message", zap.Int("line", 42))
03.Example
a.示例日志
logger := zap.NewExample()
logger.Info("example", zap.String("key", "value"))
04.Sugar
a.Printf风格
sugar := logger.Sugar()
sugar.Infow("user login", "username", "alice", "age", 25)
sugar.Infof("user %s login", "bob")
2.3 自定义Logger
01.Config结构
a.配置示例
config := zap.Config{
Level: zap.NewAtomicLevelAt(zap.InfoLevel),
Encoding: "json",
OutputPaths: []string{"stdout", "/var/log/app.log"},
}
logger, _ := config.Build()
02.NewProduction Config
a.生产配置
config := zap.NewProductionConfig()
config.OutputPaths = []string{"stdout", "./logs/app.log"}
logger, _ := config.Build()
03.NewDevelopment Config
a.开发配置
config := zap.NewDevelopmentConfig()
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
logger, _ := config.Build()
04.Build
a.创建Logger
logger, err := config.Build()
if err != nil {
panic(err)
}
defer logger.Sync()
2.4 日志级别
01.级别定义
a.所有级别
logger.Debug("debug")
logger.Info("info")
logger.Warn("warn")
logger.Error("error")
logger.DPanic("dpanic") // 开发环境panic
02.级别设置
a.动态级别
atom := zap.NewAtomicLevelAt(zap.InfoLevel)
config := zap.Config{Level: atom}
logger, _ := config.Build()
03.级别过滤
a.级别控制
// 只输出Info及以上级别
atom.SetLevel(zap.InfoLevel)
04.动态调整
a.HTTP接口
http.Handle("/log/level", atom)
// curl -X PUT localhost:8080/log/level -d level=debug
2.5 输出配置
01.OutputPaths
a.多输出
config := zap.NewProductionConfig()
config.OutputPaths = []string{"stdout", "./logs/app.log"}
02.ErrorOutputPaths
a.错误输出
config.ErrorOutputPaths = []string{"stderr", "./logs/error.log"}
03.文件输出
a.文件配置
config.OutputPaths = []string{"/var/log/app.log"}
04.多输出
a.同时输出
config.OutputPaths = []string{"stdout", "./app.log", "./debug.log"}
2.6 编码器
01.JSON编码
a.JSON格式
encoderConfig := zap.NewProductionEncoderConfig()
encoder := zapcore.NewJSONEncoder(encoderConfig)
02.Console编码
a.Console格式
encoderConfig := zap.NewDevelopmentEncoderConfig()
encoder := zapcore.NewConsoleEncoder(encoderConfig)
03.编码器配置
a.自定义配置
encoderConfig := zapcore.EncoderConfig{
TimeKey: "ts",
LevelKey: "level",
MessageKey: "msg",
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeLevel: zapcore.CapitalLevelEncoder,
}
04.自定义编码
a.实现Encoder
// 实现zapcore.Encoder接口
3 日志记录
3.1 基础日志
01.Info日志
a.信息记录
logger.Info("user login", zap.String("username", "alice"))
02.Error日志
a.错误记录
logger.Error("database error", zap.Error(err))
03.Warn日志
a.警告记录
logger.Warn("high memory usage", zap.Int("percent", 85))
04.Debug日志
a.调试记录
logger.Debug("processing request", zap.String("path", "/api/users"))
3.2 结构化日志
01.字段类型
a.类型安全
logger.Info("user info",
zap.String("name", "alice"),
zap.Int("age", 25),
zap.Bool("active", true),
)
02.复杂类型
a.灵活使用
logger.Info("data", zap.Any("value", complexStruct))
03.字段组合
a.多字段
logger.Info("request",
zap.String("method", "GET"),
zap.String("path", "/api/users"),
zap.Int("status", 200),
zap.Duration("latency", time.Millisecond*100),
)
04.性能优化
a.使用具体类型
// 好: 使用具体类型
logger.Info("msg", zap.Int("count", 10))
// 差: 使用Any
logger.Info("msg", zap.Any("count", 10))
3.3 字段类型
01.基础类型
a.常用类型
zap.String("key", "value")
zap.Int("count", 10)
zap.Int64("id", 123456)
zap.Float64("price", 99.99)
zap.Bool("active", true)
02.时间类型
a.时间处理
zap.Time("timestamp", time.Now())
zap.Duration("elapsed", time.Second*5)
03.错误类型
a.错误记录
zap.Error(err)
zap.NamedError("db_error", err)
04.复杂类型
a.高级类型
zap.Any("data", complexStruct)
zap.Binary("bytes", []byte{1, 2, 3})
3.4 上下文日志
01.With字段
a.预设字段
reqLogger := logger.With(
zap.String("request_id", "abc123"),
zap.String("user_id", "user456"),
)
reqLogger.Info("processing") // 自动包含request_id和user_id
02.上下文传递
a.Context传递
ctx := context.WithValue(context.Background(), "logger", logger)
03.字段继承
a.子Logger
childLogger := logger.With(zap.String("module", "auth"))
childLogger.Info("login") // 包含module字段
04.性能考虑
a.With开销
// With会创建新Logger,有一定开销
// 建议在请求开始时创建,复用整个请求周期
3.5 采样日志
01.采样配置
a.采样设置
config := zap.NewProductionConfig()
config.Sampling = &zap.SamplingConfig{
Initial: 100,
Thereafter: 100,
}
02.采样策略
a.频率采样
// 每秒前100条全部记录,之后每100条记录1条
03.使用场景
a.高频日志
// 适用于高频日志场景,避免日志爆炸
04.注意事项
a.信息丢失
// 采样会丢失部分日志,重要日志不要采样
3.6 条件日志
01.级别检查
a.避免计算
if logger.Core().Enabled(zap.DebugLevel) {
logger.Debug("expensive operation", zap.String("result", expensiveFunc()))
}
02.条件输出
a.性能优化
// 避免在日志级别不满足时进行昂贵的计算
03.DPanic
a.开发panic
logger.DPanic("critical error") // 开发环境panic,生产环境error
04.Check
a.条件日志
if ce := logger.Check(zap.DebugLevel, "debug msg"); ce != nil {
ce.Write(zap.String("key", "value"))
}
4 输出与格式
4.1 控制台输出
01.Console编码
a.人类可读
config := zap.NewDevelopmentConfig()
config.Encoding = "console"
logger, _ := config.Build()
02.格式配置
a.自定义格式
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
03.彩色输出
a.级别颜色
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
04.使用场景
a.开发调试
// 适用于开发环境,方便查看
4.2 文件输出
01.文件路径
a.配置路径
config.OutputPaths = []string{"./logs/app.log"}
02.文件权限
a.权限设置
// 文件权限默认0644
03.追加模式
a.日志追加
// 默认追加模式,不会覆盖
04.文件切割
a.lumberjack
import "gopkg.in/natefinch/lumberjack.v2"
w := zapcore.AddSync(&lumberjack.Logger{
Filename: "./logs/app.log",
MaxSize: 100, // MB
MaxBackups: 3,
MaxAge: 28, // days
Compress: true,
})
4.3 JSON格式
01.JSON编码
a.生产环境
config := zap.NewProductionConfig()
config.Encoding = "json"
logger, _ := config.Build()
02.字段映射
a.自定义字段
config.EncoderConfig.MessageKey = "msg"
config.EncoderConfig.LevelKey = "level"
config.EncoderConfig.TimeKey = "ts"
03.时间格式
a.时间编码
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
// 或 zapcore.EpochTimeEncoder 使用Unix时间戳
04.使用场景
a.ELK集成
// JSON格式适合日志收集系统
4.4 自定义格式
01.自定义Encoder
a.实现接口
// 实现zapcore.Encoder接口
02.格式化函数
a.自定义编码器
customTimeEncoder := func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02 15:04:05"))
}
config.EncoderConfig.EncodeTime = customTimeEncoder
03.扩展字段
a.添加字段
logger = logger.With(zap.String("app", "myapp"))
04.性能考虑
a.序列化开销
// 使用对象池减少分配
4.5 多输出
01.多个Core
a.Tee组合
consoleCore := zapcore.NewCore(
zapcore.NewConsoleEncoder(consoleConfig),
zapcore.AddSync(os.Stdout),
zap.InfoLevel,
)
fileCore := zapcore.NewCore(
zapcore.NewJSONEncoder(fileConfig),
zapcore.AddSync(file),
zap.ErrorLevel,
)
core := zapcore.NewTee(consoleCore, fileCore)
logger := zap.New(core)
02.不同配置
a.分级输出
// 控制台输出Info,文件输出Error
03.使用场景
a.文件+控制台
// 同时输出到控制台和文件
04.性能影响
a.IO开销
// 多输出会增加IO开销
4.6 日志切割
01.lumberjack
a.日志轮转
import "gopkg.in/natefinch/lumberjack.v2"
logger := &lumberjack.Logger{
Filename: "./logs/app.log",
MaxSize: 100, // MB
MaxBackups: 3,
MaxAge: 28, // days
Compress: true,
}
02.配置选项
a.参数说明
MaxSize: 100, // 单个文件最大100MB
MaxBackups: 3, // 最多保疙3个备份
MaxAge: 28, // 最多保疐28天
Compress: true, // 压缩旧文件
03.归档策略
a.自动清理
// 超过MaxAge或MaxBackups的文件会被自动删除
04.最佳实践
a.合理配置
// 根据日志量调整MaxSize
// 定期监控磁盘空间
5 高级特性
5.1 性能优化
01.零分配
a.对象池
// Zap使用对象池减少分配
02.字段类型
a.类型安全
// 好: 使用具体类型
logger.Info("msg", zap.Int("count", 10))
// 差: 使用Any
logger.Info("msg", zap.Any("count", 10))
03.采样
a.采样策略
config.Sampling = &zap.SamplingConfig{
Initial: 100,
Thereafter: 100,
}
04.异步写入
a.缓冲写入
// 使用缓冲减少IO
5.2 错误处理
01.Error字段
a.错误记录
logger.Error("operation failed", zap.Error(err))
02.错误包装
a.错误链
import "github.com/pkg/errors"
err = errors.Wrap(err, "context")
logger.Error("failed", zap.Error(err))
03.错误级别
a.级别选择
logger.Error("error")
logger.Warn("warning")
logger.DPanic("critical")
04.错误上报
a.Sentry集成
// 集成Sentry进行错误追踪
5.3 Hook机制
01.Core Hook
a.注册Hook
core = zapcore.RegisterHooks(core, func(entry zapcore.Entry) error {
// Hook逻辑
return nil
})
02.自定义Hook
a.实现Hook
// 实现自定义Hook逻辑
03.使用场景
a.日志上报
// 将日志上报到监控系统
04.性能考虑
a.异步处理
// Hook中使用异步处理避免阻塞
5.4 日志采样
01.采样配置
a.配置示例
config.Sampling = &zap.SamplingConfig{
Initial: 100,
Thereafter: 100,
}
02.采样算法
a.计数采样
// 每秒前100条全记录,之后每100条记录1条
03.使用场景
a.高频日志
// 适用于高频日志场景
04.监控告警
a.重要日志
// 重要日志不要采样
5.5 动态级别
01.AtomicLevel
a.动态调整
atom := zap.NewAtomicLevel()
config := zap.Config{Level: atom}
logger, _ := config.Build()
atom.SetLevel(zap.DebugLevel)
02.HTTP接口
a.HTTP服务
http.Handle("/log/level", atom)
http.ListenAndServe(":8080", nil)
// curl -X PUT localhost:8080/log/level -d level=debug
03.配置更新
a.热更新
// 从配置中心读取级别并更新
04.使用场景
a.线上调试
// 线上问题排查时动态开启Debug
6 集成应用
6.1 与Gin集成
01.中间件
a.日志中间件
func LoggerMiddleware(logger *zap.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
logger.Info("request",
zap.String("method", c.Request.Method),
zap.String("path", c.Request.URL.Path),
zap.Int("status", c.Writer.Status()),
zap.Duration("latency", time.Since(start)),
)
}
}
02.上下文传递
a.请求ID
reqLogger := logger.With(zap.String("request_id", requestID))
c.Set("logger", reqLogger)
03.错误日志
a.Panic恢复
defer func() {
if err := recover(); err != nil {
logger.Error("panic", zap.Any("error", err))
}
}()
04.性能日志
a.慢请求
if latency > time.Second {
logger.Warn("slow request", zap.Duration("latency", latency))
}
6.2 与gRPC集成
01.拦截器
a.Unary拦截器
func UnaryInterceptor(logger *zap.Logger) grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
start := time.Now()
resp, err := handler(ctx, req)
logger.Info("grpc call",
zap.String("method", info.FullMethod),
zap.Duration("latency", time.Since(start)),
zap.Error(err),
)
return resp, err
}
}
02.请求日志
a.方法记录
logger.Info("grpc", zap.String("method", info.FullMethod))
03.错误日志
a.gRPC错误
logger.Error("grpc error", zap.Error(err))
04.追踪集成
a.OpenTelemetry
// 集成OpenTelemetry进行分布式追踪
6.3 分布式追踪
01.TraceID
a.追踪ID
traceID := span.SpanContext().TraceID().String()
logger.With(zap.String("trace_id", traceID))
02.SpanID
a.调用链
spanID := span.SpanContext().SpanID().String()
logger.With(zap.String("span_id", spanID))
03.集成方案
a.Jaeger
// 集成Jaeger进行链路追踪
04.日志关联
a.TraceID关联
// 通过TraceID关联日志和追踪
6.4 日志收集
01.ELK集成
a.Elasticsearch
// JSON格式日志发送到Elasticsearch
02.日志格式
a.JSON格式
config.Encoding = "json"
03.日志传输
a.Filebeat
// 使用Filebeat采集日志文件
04.查询分析
a.Kibana
// 在Kibana中查询和分析日志
7 实战与最佳实践
7.1 生产环境配置
01.日志级别
a.级别设置
config := zap.NewProductionConfig()
config.Level = zap.NewAtomicLevelAt(zap.InfoLevel)
02.输出配置
a.JSON+文件
config.Encoding = "json"
config.OutputPaths = []string{"./logs/app.log"}
03.性能优化
a.采样配置
config.Sampling = &zap.SamplingConfig{
Initial: 100,
Thereafter: 100,
}
04.监控告警
a.错误监控
// 监控Error级别日志数量
7.2 性能调优
01.字段优化
a.使用具体类型
// 好
logger.Info("msg", zap.Int("count", 10))
// 差
logger.Info("msg", zap.Any("count", 10))
02.采样策略
a.高频日志采样
config.Sampling = &zap.SamplingConfig{
Initial: 100,
Thereafter: 100,
}
03.异步写入
a.缓冲写入
// 使用缓冲减少IO次数
04.资源控制
a.文件切割
&lumberjack.Logger{
Filename: "./logs/app.log",
MaxSize: 100,
MaxBackups: 3,
MaxAge: 28,
}
7.3 日志管理
01.日志分类
a.分类输出
accessLogger := logger.With(zap.String("type", "access"))
errorLogger := logger.With(zap.String("type", "error"))
02.日志切割
a.lumberjack
&lumberjack.Logger{
Filename: "./logs/app.log",
MaxSize: 100,
MaxBackups: 3,
MaxAge: 28,
Compress: true,
}
03.日志查询
a.ELK查询
// 在Kibana中使用JSON字段查询
04.日志归档
a.长期存储
// 压缩归档旧日志
7.4 安全实践
01.敏感信息
a.脱敏处理
// 不记录密码
logger.Info("login", zap.String("username", username))
// 不要记录 zap.String("password", password)
02.日志权限
a.文件权限
// 设置日志文件权限为0600
03.日志加密
a.传输加密
// 使用TLS传输日志
04.合规要求
a.数据保护
// 遵守GDPR等数据保护法规
7.5 最佳实践
01.结构化日志
a.键值对
logger.Info("user action",
zap.String("user_id", "123"),
zap.String("action", "login"),
zap.String("ip", "192.168.1.1"),
)
02.上下文信息
a.请求追踪
reqLogger := logger.With(
zap.String("request_id", requestID),
zap.String("trace_id", traceID),
)
03.错误处理
a.错误记录
logger.Error("operation failed",
zap.Error(err),
zap.String("operation", "database_query"),
)
04.性能考虑
a.级别控制
if logger.Core().Enabled(zap.DebugLevel) {
logger.Debug("debug", zap.String("data", expensiveFunc()))
}