golang?日志庫(kù)ZAP[uber-go?zap]示例詳解
golang 日志庫(kù)ZAP[uber-go zap]
1. 簡(jiǎn)要說(shuō)明
zap 是 uber 開(kāi)源的 Go 高性能日志庫(kù),支持不同的日志級(jí)別, 能夠打印基本信息等,但不支持日志的分割,這里我們可以使用 lumberjack 也是 zap 官方推薦用于日志分割,結(jié)合這兩個(gè)庫(kù)我們就可以實(shí)現(xiàn)以下功能的日志機(jī)制:
能夠?qū)⑹录涗浀轿募校皇菓?yīng)用程序控制臺(tái);日志切割能夠根據(jù)文件大小、時(shí)間或間隔等來(lái)切割日志文件;支持不同的日志級(jí)別,例如 DEBUG , INFO , WARN , ERROR 等;能夠打印基本信息,如調(diào)用文件、函數(shù)名和行號(hào),日志時(shí)間等;官網(wǎng)地址:https://github.com/uber-go/zap
2. 下載安裝
// 初始化go mod 通過(guò)mod管理擴(kuò)展包 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 。兩者之間的區(qū)別是:
- 在每一微秒和每一次內(nèi)存分配都很重要的上下文中,使用Logger。它甚至比SugaredLogger更快,內(nèi)存分配次數(shù)也更少,但它只支持強(qiáng)類型的結(jié)構(gòu)化日志記錄。
- 在性能很好但不是很關(guān)鍵的上下文中,使用SugaredLogger。它比其他結(jié)構(gòu)化日志記錄包快 4-10 倍,并且支持結(jié)構(gòu)化和 printf 風(fēng)格的日志記錄。
- 所以一般場(chǎng)景下我們使用 Sugared Logger 就足夠了。
3.1 Logger
- 通過(guò)調(diào)用zap.NewProduction()/zap.NewDevelopment()或者zap.NewExample()創(chuàng)建一個(gè) Logger 。
- 上面的每一個(gè)函數(shù)都將創(chuàng)建一個(gè) logger 。唯一的區(qū)別在于它將記錄的信息不同。例如 production logger 默認(rèn)記錄調(diào)用函數(shù)信息、日期和時(shí)間等。
- 通過(guò) Logger 調(diào)用 INFO 、 ERROR 等。
- 默認(rèn)情況下日志都會(huì)打印到應(yīng)用程序的 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") } //輸出結(jié)果: {"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") } //輸出結(jié)果: 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") } 輸出結(jié)果: {"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 對(duì)比總結(jié)
Example和Production使用的是 json 格式輸出,Development 使用行的形式輸出
- Development
- 從警告級(jí)別向上打印到堆棧中來(lái)跟蹤
- 始終打印包/文件/行(方法)
- 在行尾添加任何額外字段作為 json 字符串
- 以大寫(xiě)形式打印級(jí)別名稱
- 以毫秒為單位打印 ISO8601 格式的時(shí)間戳
- Production
- 調(diào)試級(jí)別消息不記錄
- Error , Dpanic 級(jí)別的記錄,會(huì)在堆棧中跟蹤文件, Warn 不會(huì)
- 始終將調(diào)用者添加到文件中
- 以時(shí)間戳格式打印日期
- 以小寫(xiě)形式打印級(jí)別名稱
- 在上面的代碼中,我們首先創(chuàng)建了一個(gè) Logger ,然后使用 Info / Error 等 Logger 方法記錄消息。
日志記錄器方法的語(yǔ)法是這樣的:
func (log *Logger) MethodXXX(msg string, fields ...Field)
其中 MethodXXX 是一個(gè)可變參數(shù)函數(shù),可以是 Info / Error / Debug / Panic 等。每個(gè)方法都接受一個(gè)消息字符串和任意數(shù)量的 zapcore.Field 長(zhǎng)參數(shù)。
每個(gè) zapcore.Field 其實(shí)就是一組鍵值對(duì)參數(shù)。
3.2 Sugared Logger
默認(rèn)的 zap 記錄器需要結(jié)構(gòu)化標(biāo)簽,即對(duì)每個(gè)標(biāo)簽,需要使用特定值類型的函數(shù)。
log.Info("this is info message with fileds",zap.Int("age", 24), zap.String("agender", "man"))
雖然會(huì)顯的很長(zhǎng),但是對(duì)性能要求較高的話,這是最快的選擇。也可以使用suger logger, 它基于 printf 分割的反射類型檢測(cè),提供更簡(jiǎn)單的語(yǔ)法來(lái)添加混合類型的標(biāo)簽。
我們使用 Sugared Logger 來(lái)實(shí)現(xiàn)相同的功能。
- 大部分的實(shí)現(xiàn)基本都相同;
- 惟一的區(qū)別是,我們通過(guò)調(diào)用主 logger 的.Sugar()方法來(lái)獲取一個(gè)SugaredLogger;
- 然后使用SugaredLogger以printf格式記錄語(yǔ)句;
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) } //輸出結(jié)果: 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}
如果需要,可以隨時(shí)使用記錄器上的 .Desugar() 方法從 sugar logger 切換到標(biāo)準(zhǔn)記錄器。
log := slogger.Desugar() log.Info("After Desugar; INFO message") log.Warn("After Desugar; WARN message") log.Error("After Desugar; ERROR message")
4. 將日志寫(xiě)入文件
我們將使用zap.New(…)方法來(lái)手動(dòng)傳遞所有配置,而不是使用像zap.NewProduction()這樣的預(yù)置方法來(lái)創(chuàng)建 logger 。
func New(core zapcore.Core, options ...Option) *Logger
zapcore.Core需要三個(gè)配置——Encoder,WriteSyncer,LogLevel。
Encoder :編碼器(如何寫(xiě)入日志)。我們將使用開(kāi)箱即用的 NewConsoleEncoder() ,并使用預(yù)先設(shè)置的 ProductionEncoderConfig() 。
zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())
WriterSyncer :指定日志將寫(xiě)到哪里去。我們使用 zapcore.AddSync() 函數(shù)并且將打開(kāi)的文件句柄傳進(jìn)去。
file, _ := os.Create("./test.log") writeSyncer := zapcore.AddSync(file)
Log Level :哪種級(jí)別的日志將被寫(xiě)入。
// 代碼示例: 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() 添加將調(diào)用函數(shù)信息記錄到日志中的功能。 logger := zap.New(core, zap.AddCaller()) sugarLogger = logger.Sugar() } func getEncoder() zapcore.Encoder { encoderConfig := zap.NewProductionEncoderConfig() encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder // 修改時(shí)間編碼器 // 在日志文件中使用大寫(xiě)字母記錄日志級(jí)別 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
到此這篇關(guān)于golang 日志庫(kù)ZAP[uber-go zap]詳解的文章就介紹到這了,更多相關(guān)golang 日志庫(kù)ZAP內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang 類型轉(zhuǎn)換的實(shí)現(xiàn)(斷言、強(qiáng)制、顯式類型)
將一個(gè)值從一種類型轉(zhuǎn)換到另一種類型,便發(fā)生了類型轉(zhuǎn)換,在go可以分為斷言、強(qiáng)制、顯式類型轉(zhuǎn)換,本文就詳細(xì)的介紹一下這就幾種轉(zhuǎn)換方式,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09go語(yǔ)言通過(guò)結(jié)構(gòu)體生成json示例解析
這篇文章主要為大家介紹了go語(yǔ)言通過(guò)結(jié)構(gòu)體生成json示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04Golang常用環(huán)境變量說(shuō)明與設(shè)置詳解
這篇文章主要介紹了Golang常用環(huán)境變量說(shuō)明與設(shè)置,需要的朋友可以參考下2020-02-02淺談go語(yǔ)言閉包的立即執(zhí)行和不立即執(zhí)行
Go語(yǔ)言中的閉包是一種可以訪問(wèn)其定義時(shí)所在作用域變量的特殊函數(shù),閉包可以分為立即執(zhí)行和不立即執(zhí)行兩種,本文就來(lái)介紹一下go語(yǔ)言閉包的立即執(zhí)行和不立即執(zhí)行,感興趣的可以了解一下2025-03-03Qt6.5 grpc組件使用 + golang grpc server
這篇文章主要介紹了Qt6.5 grpc組件使用+golang grpc server示例,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05