Go语言Zap日志库如何使用
导读:本文共5673字符,通常情况下阅读需要19分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 一、日志库选型需要和比较1.日志库选型需求日志性能不同日志级别可读性(包括日志采集、监控等)文件切割(不同维度分割)2.日志库比较记录一条消息和 10 个字段:PackageTimeTime % to zapObjects Allocated⚡zap2900 ns/op+0%5 allocs/op⚡zap (sugared)3475 ns/op+20%10 al... ...
目录
(为您整理了一些要点),点击可以直达。一、日志库选型需要和比较
1.日志库选型需求
日志性能
不同日志级别
可读性(包括日志采集、监控等)
文件切割(不同维度分割)
2.日志库比较
记录一条消息和 10 个字段:
使用已经有 10 个上下文字段的记录器记录消息:
记录一个静态字符串,没有任何上下文或 printf 样式的模板:
通过上面benchmark测试可以Zap性能是非常出众的。主要是大多数日志库提供的方式是基于反射的序列化和字符串格式化,这种方式代价太高,而 Zap 采取不同的方法。
避免 interface{} 使用强类型设计
封装强类型,无反射
使用零分配内存的 JSON 编码器,尽可能避免序列化开销
二、Zap(Uber-go)
1.安装
go get -u go.uber.org/zap
2.配置Zap Logger
Zap提供了两种类型的日志记录器:Sugared Logger、Logger。在每一微秒和每一次内存分配都很重要的上下文中,使用Logger,内存分配次数也更少,但它只支持强类型的结构化日志记录。对性能不是要求极致,建议使用SugaredLogger,支持结构化和 printf 风格的日志记录。
2.1.Logger
通过调用zap.NewProduction() | zap.NewDevelopment() | zap.Example()创建一个 Logger。
上面的每一个函数都将创建一个 logger。唯一的区别在于它将记录的信息不同。例如 production logger 默认记录调用函数信息、日期和时间等。
通过 Logger 调用 Info/Error 等。
默认情况下日志都会打印到应用程序的 console 界面。
packagemainimport( "errors" "go.uber.org/zap")varlogger*zap.Loggerfuncmain(){ InitLogger() logger.Debug("这是一条日志",zap.String("name","zhangSang"),zap.Int("age",18))//zap.NewProduction()默认不输出该级别日志 logger.Info("这是一条日志",zap.String("name","zhangSang"),zap.Int("age",18)) logger.Error("这是一条日志",zap.String("name","zhangSang"),zap.Error(errors.New("错误信息")))}funcInitLogger(){ logger,_=zap.NewProduction() deferlogger.Sync()}
上面代码执行结果:
{"level":"info","ts":1655165315.1104648,"caller":"test/main.go:13","msg":"这是一条日志","name":"zhangSang","age":18}
{"level":"error","ts":1655165315.1105008,"caller":"test/main.go:14","msg":"这是 一条日志","name":"zhangSang","error":"错误信息","stacktrace":"main.main\n\tD:/Go/Work/src/test/main.go:14\nruntime.main\n\tD:/Go/src/runtime/proc.go:255"
2.2.Sugared Logger
基本实现都一样,使用SugaredLogger支持Printf格式记录语句
调用logger的sugar()方法来获取一个SugaredLogger
packagemainimport( "errors" "go.uber.org/zap")varlogger*zap.Loggervarsugar*zap.SugaredLoggerfuncmain(){ InitLogger() sugar.Debug("这是一条日志",zap.String("name","zhangSang"),zap.Int("age",18))//zap.NewProduction()默认不输出该级别日志 sugar.Info("这是一条日志",zap.String("name","zhangSang"),zap.Int("age",18)) sugar.Error("这是一条日志",zap.String("name","zhangSang"),zap.Error(errors.New("错误信息")))}funcInitLogger(){ logger,_=zap.NewProduction() deferlogger.Sync() sugar=logger.Sugar()}
上面代码执行结果:
{"level":"info","ts":1655165815.3873067,"caller":"test/main.go:14","msg":"这是一条日志{name 15 0 zhangSang <nil>} {age 11 18 <nil>}"}
{"level":"error","ts":1655165815.3880382,"caller":"test/main.go:15","msg":"这是一条日志{name 15 0 zhangSang <nil>} {error 26 0 错误信息}","stacktrace":"main.main\n\tD:/GoWork/src/test/main.go:15\nruntime.main\n\tD:/Go/src/runtime/proc.go:255"}
2.3. 配置Logger
zap.New()
方法来手动传递所有配置,而不是使用像zap.NewProduction()
这样的预置方法来创建 logger;zapcore.Core需要三个配置——Encoder,WriteSyncer,LogLevel。
funcNew(corezapcore.Core,options...Option)*Logger
1.Encoder: 编码器 (配置日志格式)。此处使用NewJSONEncoder() (如果不喜欢JSON格式日志,NewConsoleEncoder()指定普通 Encoder),并使用预先设置的ProductionEncoderConfig(),ProductionEncoderConfig()返回一个自定义的EncoderConfig。
funcgetEncoder()zapcore.Encoder{ encoderConfig:=zap.NewProductionEncoderConfig() returnzapcore.NewJSONEncoder(encoderConfig)}
2.WriterSyncer :指定日志写到何处。使用zapcore.AddSync()函数并且将打开的文件句柄传入。
funcgetLogWriter()zapcore.WriteSyncer{ file,_:=os.OpenFile("./test.log",os.O_CREATE|os.O_APPEND|os.O_RDWR,0666)//打开文件(不存在创建) returnzapcore.AddSync(file)}
3.Log Level-指定日志级别
funcInitLogger(){ writeSyncer:=getLogWriter() encoder:=getEncoder() core:=zapcore.NewCore(encoder,writeSyncer,zapcore.DebugLevel)//DebugLevel logger=zap.New(core) deferlogger.Sync() sugarLogger=logger.Sugar()}
大家将上面的方法新增测试代码中,运行结果:
4.时间格式化处理
funcgetEncoder()zapcore.Encoder{ encoderConfig:=zap.NewProductionEncoderConfig() encoderConfig.EncodeTime=customTimeEncoder returnzapcore.NewJSONEncoder(encoderConfig)}funccustomTimeEncoder(ttime.Time,enczapcore.PrimitiveArrayEncoder){ enc.AppendString(t.Format("2006-01-0215:04:05.000"))}
运行结果:
5.输出文件名和行号
zap.New()中加上zap.AddCaller()。
funcInitLogger(){ writeSyncer:=getLogWriter() encoder:=getEncoder() core:=zapcore.NewCore(encoder,writeSyncer,zapcore.DebugLevel)//DebugLevel logger=zap.New(core,zap.AddCaller()) deferlogger.Sync() sugarLogger=logger.Sugar()}
运行结果:
三.使用 Lumberjack 进行日志切割归档
1. 安装
go get -u github.com/natefinch/lumberjack
2.Zap logger中使用Lumberjack
funcgetLogWriter()zapcore.WriteSyncer{ lumberJackLogger:=&lumberjack.Logger{ Filename:"./test.log",//日志文件位置 MaxSize:1,//进行切割之前,日志文件最大值(单位:MB),默认100MB MaxBackups:10,//保留旧文件的最大个数 MaxAge:1,//保留旧文件的最大天数 Compress:false,//是否压缩/归档旧文件 } returnzapcore.AddSync(lumberJackLogger)}
3.完整代码
packagemainimport( "github.com/natefinch/lumberjack" "go.uber.org/zap" "go.uber.org/zap/zapcore" "time")varlogger*zap.Loggervarsugar*zap.SugaredLoggerfuncmain(){ InitLogger() fori:=0;i<99999;i++{ sugar.Debugf("查询用户信息开始id:%d",1) sugar.Infof("查询用户信息成功name:%sage:%d","zhangSan",20) sugar.Errorf("查询用户信息失败error:%v","未该查询到该用户信息") }}funcInitLogger(){ writeSyncer:=getLogWriter() encoder:=getEncoder() core:=zapcore.NewCore(encoder,writeSyncer,zapcore.DebugLevel) logger=zap.New(core,zap.AddCaller()) deferlogger.Sync() sugar=logger.Sugar()}funcgetEncoder()zapcore.Encoder{ encoderConfig:=zap.NewProductionEncoderConfig() encoderConfig.EncodeTime=customTimeEncoder returnzapcore.NewJSONEncoder(encoderConfig)}funcgetLogWriter()zapcore.WriteSyncer{ lumberJackLogger:=&lumberjack.Logger{ Filename:"./test.log",//日志文件位置 MaxSize:1,//进行切割之前,日志文件最大值(单位:MB),默认100MB MaxBackups:5,//保留旧文件的最大个数 MaxAge:1,//保留旧文件的最大天数 Compress:false,//是否压缩/归档旧文件 } returnzapcore.AddSync(lumberJackLogger)}funccustomTimeEncoder(ttime.Time,enczapcore.PrimitiveArrayEncoder){ enc.AppendString(t.Format("2006-01-0215:04:05.000"))}
在main()函数中循环9999次输出日志,运行结果:
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
Go语言Zap日志库如何使用的详细内容,希望对您有所帮助,信息来源于网络。