Zap是由Uber开发的高性能Go日志库,特别适合后端服务。
入门:
第一目:为什么要选择Zap?
在Go语言的日志库中,流行的有 zap、logrus...甚至还有Go自带的原生的log。
zap:极致性能(低延迟、低内存占用)、支持多种日志级别、偏底层、Uber官方维护并持续更新
Logrus:灵活易用、支持多种日志级别、高层封装支持全局调用、基本停滞更新
原生log包:简单易用的基础工具、学习成本低。高并发场景下性能也较低(文末有解释)
第二目:安装Zap
go get -u go.uber.org/zap
第三目:go语言简答的启动
package main import ( "go.uber.org/zap" "time" ) func main() { // 创建生产环境使用的Logger(JSON格式) logger, _ := zap.NewProduction() defer logger.Sync() // 刷新缓冲区 // Sync的作用,就是强制输出还在缓存区的内容 // 记录不同级别的日志 logger.Info("服务启动", zap.String("service", "user-api"), zap.Time("start_time", time.Now()), ) // 打印 logger.Warn("数据库连接缓慢", zap.Duration("duration", 150*time.Millisecond), ) logger.Error("无法连接Redis", zap.String("host", "redis:6379"), zap.Error(err), // 假设有err变量 ) }
输出示例
{"level":"info","ts":1690000000.1234567,"msg":"服务启动","service":"user-api","start_time":"2023-07-22T10:00:00Z"} {"level":"warn","ts":1690000001.2345678,"msg":"数据库连接缓慢","duration":0.15} {"level":"error","ts":1690000002.3456789,"msg":"无法连接Redis","host":"redis:6379","error":"connection refused"}
进阶:
第一目:自定义Logger配置:
func main() { // 创建自定义配置 config := zap.NewProductionConfig() // 修改配置 config.Level = zap.NewAtomicLevelAt(zap.DebugLevel) // 设置日志级别 config.OutputPaths = []string{"stdout", "logs/app.log"} // 输出到控制台和文件 config.EncoderConfig.TimeKey = "timestamp" // 自定义时间字段名 config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder // ISO时间格式 // 构建Logger logger, err := config.Build() if err != nil { panic(err) } defer logger.Sync() // 使用Logger logger.Debug("调试信息", zap.String("module", "authentication")) }
第二目:创建开发环境Logger(易读格式)
func main() { // 开发环境使用更易读的控制台输出 logger, _ := zap.NewDevelopment() defer logger.Sync() logger.Info("开发模式日志", zap.String("url", "/api/users"), zap.Int("status", 200), ) } // 2023-07-22T10:00:00.123Z INFO 开发模式日志 {"url": "/api/users", "status": 200}
第三目:使用Sugar Logger(简化语法)
Sugar是zap提供的一种更灵活,更易用的日志记录接口。
格式化字符串与结构字段,语法更接近传统日志库,缺点就是性能略低。
func main() { logger, _ := zap.NewProduction() defer logger.Sync() // 创建Sugar Logger sugar := logger.Sugar() // 简化语法(性能略低于标准Logger) sugar.Infow("用户注册成功", "user_id", 12345, "email", "user@example.com", "registration_time", time.Now(), ) // 格式化日志 sugar.Infof("新请求: %s %s", "GET", "/api/users") } {"level":"info","ts":1753187495.5488393,"caller":"zap/main.go:92","msg":"用户注册成功","user_id":12345,"email":"user@example.com","registration_time":1753187495.5488393}
第四目:封装Logger(推荐)
对zap,封装成Init与Sync两个函数,需要时,调用即可。
// logger/logger.go package logger import ( "go.uber.org/zap" ) var Log *zap.Logger func Init(debug bool) { var err error if debug { Log, err = zap.NewDevelopment() } else { Log, err = zap.NewProduction() } if err != nil { panic(err) } // 添加全局字段(服务名、版本等) Log = Log.With( zap.String("service", "user-service"), zap.String("version", "1.0.0"), ) } func Sync() { _ = Log.Sync() }
第五目:在项目中如何调用
// main.go package main import ( "your-project/logger" "net/http" ) func main() { // 初始化Logger logger.Init(true) // 开发模式 defer logger.Sync() http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { logger.Log.Info("处理请求", zap.String("path", r.URL.Path), zap.String("method", r.Method), ) w.Write([]byte("Hello, World!")) }) logger.Log.Info("启动HTTP服务", zap.String("port", "8080")) http.ListenAndServe(":8080", nil) }
第六目:日志切割
一、安装Lumberjack:
go get gopkg.in/natefinch/lumberjack.v2
二、配置日志切割
import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" ) func getLogWriter() zapcore.WriteSyncer { lumberJackLogger := &lumberjack.Logger{ Filename: "logs/app.log", // 日志文件路径 MaxSize: 100, // 单个文件最大大小(MB) MaxBackups: 5, // 保留旧文件的最大个数 MaxAge: 30, // 保留旧文件的最大天数 Compress: true, // 是否压缩/归档旧文件 } return zapcore.AddSync(lumberJackLogger) } func main() { encoder := getEncoder() writer := getLogWriter() core := zapcore.NewCore(encoder, writer, zapcore.DebugLevel) logger := zap.New(core) defer logger.Sync() // 使用logger... } func getEncoder() zapcore.Encoder { encoderConfig := zap.NewProductionEncoderConfig() encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder return zapcore.NewJSONEncoder(encoderConfig) }
项目中,常用的就这些。
后续会补充。
日志级别的合理使用:
- DEBUG:调试信息
- INFO:重要流程信息
- WARN:预期之外但可恢复的情况
- ERROR:需要立即关注的错误
- DPANIC/ PANIC/FATAL:严重错误(谨慎使用)
注:
- Zap 使用 无反射设计(通过预定义字段类型避免运行时反射),且 内存预分配 减少 GC 压力。
- 原生 log 依赖
fmt.Sprintf()进行字符串拼接,在高并发下性能损耗显著。