Zap日志库实战教程
·
Zap日志库实战教程
一、zap日志库介绍
Zap是非常快的、结构化的,分日志级别的Go日志库,同时提供了结构化日志记录和printf风格的日志记录。同时提供了两种类型的日志记录器sugared Logger和logger
Zap是由https://github.com/uber-go/zap Uber开源的高性能日志库。
特点:
- 极致性能
- 结构化日志
- JSON格式输出
- 支持日志切割
- 支持日志分级
- 支持多输出
- 适合微服务和K8S环境
默认logger的优缺点
优势
它最大的优点是使用非常简单。我们可以设置任何io.Writer作为日志记录输出并向其发送要写入的日志。
劣势
仅限基本的日志级别
只有一个Print选项。不支持INFO/DEBUG等多个级别。
对于错误日志,它有Fatal和Panic
Fatal日志通过调用os.Exit(1)来结束程序
Panic日志在写入日志消息之后抛出一个panic
但是它缺少一个ERROR日志级别,这个级别可以在不抛出panic或退出程序的情况下记录错误
缺乏日志格式化的能力——例如记录调用者的函数名和行号,格式化日期和时间格式。等等。
不提供日志切割的能力。
二、安装zap日志库
go get -u go.uber.org/zap
日志切割
go get gopkg.in/natefinch/lumberjack.v2
日志等级
Debug
Info
Warn
Error
DPanic
Panic
Fatal
三、创建Logger
开发环境
logger, _ := zap.NewDevelopment()
生产环境
logger, _ := zap.NewProduction()
三、配置zap logger
第一种、配置Logger
Logger
通过调用zap.NewProduction()/zap.NewDevelopment()或者zap.Example()创建一个Logger。
上面的每一个函数都将创建一个logger。唯一的区别在于它将记录的信息不同。例如production logger默认记录调用函数信息、日期和时间等。
通过Logger调用Info/Error等。
默认情况下日志都会打印到应用程序的console界面
示例:
var logger *zap.Logger //定义全局logger实例
func main() {
InitLogger()
defer logger.Sync() //在程序退出之前,将日志都刷到磁盘上
simpleHttpGet("www.google.com")
simpleHttpGet("http://www.google.com")
}
func InitLogger() {
logger, _ = zap.NewProduction()
}
//测试
func simpleHttpGet(url string) {
resp, err := http.Get(url)
if err != nil {
logger.Error(
"Error fetching url..",
zap.String("url", url),
zap.Error(err))
} else {
logger.Info("Success..",
zap.String("statusCode", resp.Status),
zap.String("url", url))
resp.Body.Close()
}
}
打印结果,以json形式打印:
{"level":"error","ts":1572159218.912792,"caller":"zap_demo/temp.go:25","msg":"Error fetching url..","url":"www.sogo.com","error":"Get www.sogo.com: unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\t/Users/q1mi/zap_demo/temp.go:25\nmain.main\n\t/Users/q1mi/zap_demo/temp.go:14\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:203"}
{"level":"info","ts":1572159219.1227388,"caller":"zap_demo/temp.go:30","msg":"Success..","statusCode":"200 OK","url":"http://www.sogo.com"}
代码分析
在上面的代码中,我们首先创建了一个Logger,然后使用Info/ Error等Logger方法记录消息。
日志记录器方法的语法是这样的:
func (log *Logger) MethodXXX(msg string, fields ...Field)
其中MethodXXX是一个可变参数函数,可以是Info / Error/ Debug / Panic等。每个方法都接受一个消息字符串和任意数量的zapcore.Field场参数。
每个zapcore.Field其实就是一组键值对参数。
第二种 Sugared Logger
大部分的实现基本都相同。
惟一的区别是,我们通过调用主logger的. Sugar()方法来获取一个SugaredLogger。
然后使用SugaredLogger以printf格式记录语句
示例
var sugarLogger *zap.SugaredLogger
func main() {
InitLogger()
defer sugarLogger.Sync()
simpleHttpGet("www.google.com")
simpleHttpGet("http://www.google.com")
}
func InitLogger() {
logger, _ := zap.NewProduction()
sugarLogger = logger.Sugar()
}
func simpleHttpGet(url string) {
sugarLogger.Debugf("Trying to hit GET request for %s", url)
resp, err := http.Get(url)
if err != nil {
sugarLogger.Errorf("Error fetching URL %s : Error = %s", url, err)
} else {
sugarLogger.Infof("Success! statusCode = %s for URL %s", resp.Status, url)
resp.Body.Close()
}
}
四、zap日志自定义配置
1、将日志写入文件 的配置
步骤:
使用zap.New(…)方法来手动传递所有配置,而不是使用像zap.NewProduction()这样的预置方法来创建logger。
func New(core zapcore.Core, options ...Option) *Logger
zapcore.Core需要三个配置——Encoder,WriteSyncer,LogLevel。
编码器(Encoder): 使用NewJSONEncoder(),并使用预先设置的ProductionEncoderConfig()
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
WriteSyncer: 指定将日志写到哪里, 使用zapcore.AddSync()函数并且将打开的文件句柄传进去
file, _ := os.Create("./test.log")
writeSyncer := zapcore.AddSync(file)
LogLevel: 哪种级别的日志将被写入
//示例 修改上述部分中的Logger代码,并重写InitLogger()方法。其余方法—main() /SimpleHttpGet()保持不变。
func InitLogger() {
writeSyncer := getLogWriter()
encoder := getEncoder()
core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
logger := zap.New(core)
sugarLogger = logger.Sugar()
}
func getEncoder() zapcore.Encoder {
return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
}
func getLogWriter() zapcore.WriteSyncer {
file, _ := os.Create("./test.log")
return zapcore.AddSync(file)
}
//打印结果
{"level":"debug","ts":1572160754.994731,"msg":"Trying to hit GET request for www.sogo.com"}
{"level":"error","ts":1572160754.994982,"msg":"Error fetching URL www.sogo.com : Error = Get www.sogo.com: unsupported protocol scheme \"\""}
将json格式修改为普通格式
return zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())
修改日志中打印的时间格式
func getEncoder() zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder //修改修改时间编码器
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder //在日志文件中使用大写字母记录日志级别
return zapcore.NewConsoleEncoder(encoderConfig)
}
添加AddCallerSkip,通过日志获取精确的行数,同时需要在new方法中调用上述的两处修改
logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
将日志输出到多个位置
func getLogWriter() zapcore.WriteSyncer {
file, _ := os.Create("./test.log")
// 利用io.MultiWriter支持文件和终端两个输出目标
ws := io.MultiWriter(file, os.Stdout)
return zapcore.AddSync(ws)
}
将err日志单独输出到文件
func InitLogger() {
encoder := getEncoder()
// test.log记录全量日志
logF, _ := os.Create("./test.log")
c1 := zapcore.NewCore(encoder, zapcore.AddSync(logF), zapcore.DebugLevel)
// test.err.log记录ERROR级别的日志
errF, _ := os.Create("./test.err.log")
c2 := zapcore.NewCore(encoder, zapcore.AddSync(errF), zap.ErrorLevel)
// 使用NewTee将c1和c2合并到core
core := zapcore.NewTee(c1, c2)
logger = zap.New(core, zap.AddCaller())
}
五、按日志大小切割日志
安装日志切割库
go get gopkg.in/natefinch/lumberjack.v2
在zap logger中添加lumberjack
修改WriteSyncer代码。我们将按照下面的代码修改getLogWriter()函数:
func getLogWriter() zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{ //从之前的os.create替换为lumberjack.Logger
Filename: "./test.log", //日志文件
MaxSize: 10, //单位是MB 文件的最大量存储10MB
MaxBackups: 5, //保留旧日志的最大个数
MaxAge: 30, //保留旧文件的最大天数
Compress: false, //是否压缩日志
}
return zapcore.AddSync(lumberJackLogger)
}
同时输出到日志文件和控制台
core := zapcore.NewTee(
fileCore,
consoleCore,
)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)