golang 日志库ZAP[uber-go zap]示例详解
作者:nbplus_007
golang 日志库ZAP[uber-go zap]
1. 简要说明
zap 是 uber 开源的 Go 高性能日志库,支持不同的日志级别, 能够打印基本信息等,但不支持日志的分割,这里我们可以使用 lumberjack 也是 zap 官方推荐用于日志分割,结合这两个库我们就可以实现以下功能的日志机制:
能够将事件记录到文件中,而不是应用程序控制台;日志切割能够根据文件大小、时间或间隔等来切割日志文件;支持不同的日志级别,例如 DEBUG , INFO , WARN , ERROR 等;能够打印基本信息,如调用文件、函数名和行号,日志时间等;官网地址:https://github.com/uber-go/zap
2. 下载安装
// 初始化go mod 通过mod管理扩展包 go mod init zaplog //使用下面命令安装 go get -u go.uber.org/zap //如果下载失败,则使用以下命令重新下载安装 go get github.com/uber-go/zap //下载安装成功后还有如下提示: package github.com/uber-go/zap: code in directory src/github.com/uber-go/zap expects import "go.uber.org/zap"
3. 配置 zap Logger
zap 提供了两种类型的日志记录器—和 Logger 和 Sugared Logger 。两者之间的区别是:
- 在每一微秒和每一次内存分配都很重要的上下文中,使用Logger。它甚至比SugaredLogger更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。
- 在性能很好但不是很关键的上下文中,使用SugaredLogger。它比其他结构化日志记录包快 4-10 倍,并且支持结构化和 printf 风格的日志记录。
- 所以一般场景下我们使用 Sugared Logger 就足够了。
3.1 Logger
- 通过调用zap.NewProduction()/zap.NewDevelopment()或者zap.NewExample()创建一个 Logger 。
- 上面的每一个函数都将创建一个 logger 。唯一的区别在于它将记录的信息不同。例如 production logger 默认记录调用函数信息、日期和时间等。
- 通过 Logger 调用 INFO 、 ERROR 等。
- 默认情况下日志都会打印到应用程序的 console 界面。
3.1.1 NewExample
//代码示例: package main import ( "go.uber.org/zap" ) func main() { log := zap.NewExample() log.Debug("this is debug message") log.Info("this is info message") log.Info("this is info message with fileds", zap.Int("age", 24), zap.String("agender", "man")) log.Warn("this is warn message") log.Error("this is error message") log.Panic("this is panic message") } //输出结果: {"level":"debug","msg":"this is debug message"} {"level":"info","msg":"this is info message"} {"level":"info","msg":"this is info message with fileds","age":24,"agender":"man"} {"level":"warn","msg":"this is warn message"} {"level":"error","msg":"this is error message"} {"level":"panic","msg":"this is panic message"} panic: this is panic message
3.1.2 NewDevelopment
//代码示例: func main() { log, _ := zap.NewDevelopment() log.Debug("this is debug message") log.Info("this is info message") log.Info("this is info message with fileds", zap.Int("age", 24), zap.String("agender", "man")) log.Warn("this is warn message") log.Error("this is error message") // log.DPanic("This is a DPANIC message") // log.Panic("this is panic message") // log.Fatal("This is a FATAL message") } //输出结果: 2020-06-12T18:51:11.457+0800 DEBUG task/main.go:9 this is debug message 2020-06-12T18:51:11.457+0800 INFO task/main.go:10 this is info message 2020-06-12T18:51:11.457+0800 INFO task/main.go:11 this is info message with fileds {"age": 24, "agender": "man"} 2020-06-12T18:51:11.457+0800 WARN task/main.go:13 this is warn message main.main /home/wohu/GoCode/src/task/main.go:13 runtime.main /usr/local/go/src/runtime/proc.go:200 2020-06-12T18:51:11.457+0800 ERROR task/main.go:14 this is error message main.main /home/wohu/GoCode/src/task/main.go:14 runtime.main /usr/local/go/src/runtime/proc.go:200
3.1.3 NewProduction
代码示例: func main() { log, _ := zap.NewProduction() log.Debug("this is debug message") log.Info("this is info message") log.Info("this is info message with fileds", zap.Int("age", 24), zap.String("agender", "man")) log.Warn("this is warn message") log.Error("this is error message") // log.DPanic("This is a DPANIC message") // log.Panic("this is panic message") // log.Fatal("This is a FATAL message") } 输出结果: {"level":"info","ts":1591959367.316352,"caller":"task/main.go:10","msg":"this is info message"} {"level":"info","ts":1591959367.3163702,"caller":"task/main.go:11","msg":"this is info message with fileds","age":24,"agender":"man"} {"level":"warn","ts":1591959367.3163917,"caller":"task/main.go:13","msg":"this is warn message"} {"level":"error","ts":1591959367.3163974,"caller":"task/main.go:14","msg":"this is error message","stacktrace":"main.main\n\t/home/wohu/GoCode/src/task/main.go:14\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:200"}
3.1.4 对比总结
Example和Production使用的是 json 格式输出,Development 使用行的形式输出
- Development
- 从警告级别向上打印到堆栈中来跟踪
- 始终打印包/文件/行(方法)
- 在行尾添加任何额外字段作为 json 字符串
- 以大写形式打印级别名称
- 以毫秒为单位打印 ISO8601 格式的时间戳
- Production
- 调试级别消息不记录
- Error , Dpanic 级别的记录,会在堆栈中跟踪文件, Warn 不会
- 始终将调用者添加到文件中
- 以时间戳格式打印日期
- 以小写形式打印级别名称
- 在上面的代码中,我们首先创建了一个 Logger ,然后使用 Info / Error 等 Logger 方法记录消息。
日志记录器方法的语法是这样的:
func (log *Logger) MethodXXX(msg string, fields ...Field)
其中 MethodXXX 是一个可变参数函数,可以是 Info / Error / Debug / Panic 等。每个方法都接受一个消息字符串和任意数量的 zapcore.Field 长参数。
每个 zapcore.Field 其实就是一组键值对参数。
3.2 Sugared Logger
默认的 zap 记录器需要结构化标签,即对每个标签,需要使用特定值类型的函数。
log.Info("this is info message with fileds",zap.Int("age", 24), zap.String("agender", "man"))
虽然会显的很长,但是对性能要求较高的话,这是最快的选择。也可以使用suger logger, 它基于 printf 分割的反射类型检测,提供更简单的语法来添加混合类型的标签。
我们使用 Sugared Logger 来实现相同的功能。
- 大部分的实现基本都相同;
- 惟一的区别是,我们通过调用主 logger 的.Sugar()方法来获取一个SugaredLogger;
- 然后使用SugaredLogger以printf格式记录语句;
func main() { logger, _ := zap.NewDevelopment() slogger := logger.Sugar() slogger.Debugf("debug message age is %d, agender is %s", 19, "man") slogger.Info("Info() uses sprint") slogger.Infof("Infof() uses %s", "sprintf") slogger.Infow("Infow() allows tags", "name", "Legolas", "type", 1) } //输出结果: 2020-06-12T19:23:54.184+0800 DEBUG task/main.go:11 debug message age is 19, agender is man 2020-06-12T19:23:54.185+0800 INFO task/main.go:12 Info() uses sprint 2020-06-12T19:23:54.185+0800 INFO task/main.go:13 Infof() uses sprintf 2020-06-12T19:23:54.185+0800 INFO task/main.go:14 Infow() allows tags {"name": "Legolas", "type": 1}
如果需要,可以随时使用记录器上的 .Desugar() 方法从 sugar logger 切换到标准记录器。
log := slogger.Desugar() log.Info("After Desugar; INFO message") log.Warn("After Desugar; WARN message") log.Error("After Desugar; ERROR message")
4. 将日志写入文件
我们将使用zap.New(…)方法来手动传递所有配置,而不是使用像zap.NewProduction()这样的预置方法来创建 logger 。
func New(core zapcore.Core, options ...Option) *Logger
zapcore.Core需要三个配置——Encoder,WriteSyncer,LogLevel。
Encoder :编码器(如何写入日志)。我们将使用开箱即用的 NewConsoleEncoder() ,并使用预先设置的 ProductionEncoderConfig() 。
zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())
WriterSyncer :指定日志将写到哪里去。我们使用 zapcore.AddSync() 函数并且将打开的文件句柄传进去。
file, _ := os.Create("./test.log") writeSyncer := zapcore.AddSync(file)
Log Level :哪种级别的日志将被写入。
// 代码示例: package main import ( "os" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) var sugarLogger *zap.SugaredLogger func InitLogger() { encoder := getEncoder() writeSyncer := getLogWriter() core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel) // zap.AddCaller() 添加将调用函数信息记录到日志中的功能。 logger := zap.New(core, zap.AddCaller()) sugarLogger = logger.Sugar() } func getEncoder() zapcore.Encoder { encoderConfig := zap.NewProductionEncoderConfig() encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder // 修改时间编码器 // 在日志文件中使用大写字母记录日志级别 encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // NewConsoleEncoder 打印更符合人们观察的方式 return zapcore.NewConsoleEncoder(encoderConfig) } func getLogWriter() zapcore.WriteSyncer { file, _ := os.Create("./test.log") return zapcore.AddSync(file) } func main() { InitLogger() sugarLogger.Info("this is info message") sugarLogger.Infof("this is %s, %d", "aaa", 1234) sugarLogger.Error("this is error message") sugarLogger.Info("this is info message") } // 输出日志文件: 2020-06-16T09:01:06.192+0800 INFO task/main.go:40 this is info message 2020-06-16T09:01:06.192+0800 INFO task/main.go:41 this is aaa, 1234 2020-06-16T09:01:06.192+0800 ERROR task/main.go:42 this is error message 2020-06-16T09:01:06.192+0800 INFO task/main.go:43 this is info message
到此这篇关于golang 日志库ZAP[uber-go zap]详解的文章就介绍到这了,更多相关golang 日志库ZAP内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!