golang 日志库ZAP[uber-go zap]详解

golang 日志库ZAP[uber-go zap]

1. 简要说明

zap 是 uber 开源的 Go 高性能日志库,支持不同的日志级别, 能够打印基本信息等,但不支持日志的分割,这里我们可以使用 lumberjack 也是 zap 官方推荐用于日志分割,结合这两个库我们就可以实现以下功能的日志机制:

  • 能够将事件记录到文件中,而不是应用程序控制台;
  • 日志切割能够根据文件大小、时间或间隔等来切割日志文件;
  • 支持不同的日志级别,例如 DEBUG , INFO , WARN , ERROR 等;
  • 能够打印基本信息,如调用文件、函数名和行号,日志时间等;
  • 官网地址:https://github.com/uber-go/zap

福利彩蛋:没有好玩的 API 接口?上百款免费接口等你来,免费 API,免费 API 大全

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

福利彩蛋:没有好玩的 API 接口?上百款免费接口等你来,免费 API,免费 API 大全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值