Go 語言怎麼使用 zap 日誌庫?
大家好,我是 frank。
歡迎大家關注「Golang 語言開發棧」公衆號。
01 介紹
我們在之前的文章中介紹過標準庫 log
包的使用方式,它雖然使用方便,但是它支持的功能比較簡單。
本文我們介紹 uber 開源的日誌庫 zap
,首先使用 Gin 框架構建一個 Web 應用,然後通過在該 Web 應用中記錄日誌,來介紹 zap
的使用方式。
最後,我們再使用開源的日誌切割庫 lumberjack
,進行日誌切割。
02 使用 Gin 構建一個 Web 應用
本文重點不是介紹 gin 框架的使用方式,所以我們僅使用 gin 框架構建一個簡單的 Web 應用,代碼如下:
func main() {
r := gin.Default()
r.GET("/ping", ping)
r.Run()
}
func ping(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
}
閱讀上面這段代碼,訪問 http://127.0.0.1:8080/ping
,返回結果是 {"message":"pong"}
。
然後,我們使用 zap
記錄 ping
函數的請求日誌。
03 Gin 框架使用 zap 日誌庫
Zap 支持兩種模式,分別是 SugaredLogger
和 Logger
,其中 SugaredLogger
模式比 Logger
模式執行速度更快。
SugaredLogger 模式
使用 Zap 日誌庫,首先需要使用 New
函數創建一個 Logger
,代碼如下:
func New(core zapcore.Core, options ...Option) *Logger
使用 New
函數,接收一個 zapcore.Core
類型的參數和一個 Option
類型的可選參數,返回一個 *Logger
。
其中 zap.Core
類型的參數,可以使用 NewCore
函數創建,接收三個參數,分別是 zapcore.Encoder
類型,zapcore.WriteSyncer
類型和 zapcore.LevelEnabler
類型,分別用於指定日誌格式、日誌路徑和日誌級別。
func NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler) Core
其中 zapcore.Encoder
類型的參數,可以使用 NewProductionEncoderConfig
函數創建,返回一個用於生產環境的固定日誌編碼配置。
// NewProductionEncoderConfig returns an opinionated EncoderConfig for
// production environments.
func NewProductionEncoderConfig() zapcore.EncoderConfig {
return zapcore.EncoderConfig{
TimeKey: "ts",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
FunctionKey: zapcore.OmitKey,
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.EpochTimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
}
我們可以修改任意配置選項的值。
其中 zapcore.WriteSyncer
類型的參數,可以使用 AddSync
函數創建,該函數接收一個 io.Writer
類型的參數。
func AddSync(w io.Writer) WriteSyncer
其中 zapcore.LevelEnabler
類型的參數,可以使用 zapcore
包定義的常量 zapcore.DebugLevel
,該常量是 zapcore.Level
類型,並且 zapcore.Level
類型實現了 zapcore.LevelEnabler
接口。
完整代碼:
var sugaredLogger *zap.SugaredLogger
func main() {
InitLogger()
defer sugaredLogger.Sync()
r := gin.Default()
r.GET("/ping", ping)
r.Run()
}
func ping(c *gin.Context) {
sugaredLogger.Debug("call func ping")
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
}
func InitLogger() {
core := zapcore.NewCore(enc(), ws(), enab())
logger := zap.New(core)
sugaredLogger = logger.Sugar()
}
func enc() zapcore.Encoder {
cfg := zap.NewProductionEncoderConfig()
cfg.TimeKey = "time"
cfg.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05")
return zapcore.NewJSONEncoder(cfg)
}
func ws() zapcore.WriteSyncer {
logFileName := fmt.Sprintf("./%v.log", time.Now().Format("2006-01-02"))
logFile, err := os.Create(logFileName)
if err != nil {
log.Fatal(err)
}
return zapcore.AddSync(logFile)
}
func enab() zapcore.LevelEnabler {
return zapcore.DebugLevel
}
運行程序,執行 curl http://127.0.0.1:8080/ping
。
可以看到,生成的日誌文件 xxx.log
,文件中是 json
格式的日誌內容,我們可以根據實際需求修改爲其他格式。
開發中,可能我們希望日誌可以同時輸出到日誌文件和終端中,可以使用函數 NewMultiWriteSyncer
,代碼如下:
func wsV2() zapcore.WriteSyncer {
return zapcore.NewMultiWriteSyncer(ws(), zapcore.AddSync(os.Stdout))
}
除了使用
zap.New()
創建Logger
之外,Zap 還提供了開箱即用的三種創建Logger
的方式,分別是函數NewProduction
,NewDevelopment
和Example()
,感興趣的讀者朋友們,可以試用一下。
Logger 模式
接下來,我們簡單介紹一下 Logger
模式,它主要用於性能和類型安全比較重要的場景中,但是,它沒有 SugaredLogger
模式簡單易用,我們可以根據實際場景選擇使用哪種模式。
我們修改一下現有代碼,新創建 InitLoggerV2
函數,其中 enc
,ws
和 enab
函數的代碼與 SugaredLogger
模式保持一致。
var loggerV2 *zap.Logger
func main() {
InitLoggerV2()
defer loggerV2.Sync()
r := gin.Default()
r.GET("/ping", ping)
r.Run()
}
func ping(c *gin.Context) {
loggerV2.Debug("call func ping", zap.Int("code", 200))
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
}
func InitLoggerV2() {
core := zapcore.NewCore(enc(), ws(), enab())
loggerV2 = zap.New(core)
}
閱讀上面這段代碼,我們可以發現,在使用 zap
記錄日誌時,我們需要顯示指定數據類型,一般用於性能和類型安全比較重要的場景中。
04 zap 日誌庫使用 lumberjack 庫進行日誌切割
Zap 日誌庫也不支持日誌切割的功能,我們可以使用 lumberjack
日誌切割庫進行日誌切割,關於 lumberjack
庫的使用方式,我們在之前的文章介紹過,此處不再重複介紹,直接上代碼:
func wsV3() zapcore.WriteSyncer {
logFileName := fmt.Sprintf("./%v.log", time.Now().Format("2006-01-02"))
lumberjackLogger := &lumberjack.Logger{
Filename: logFileName,
MaxSize: 1,
MaxBackups: 3,
MaxAge: 28,
Compress: false,
}
return zapcore.AddSync(lumberjackLogger)
}
lumberjack.Logger
的字段含義:
-
Filename 日誌保存文件路徑
-
MaxSize 日誌文件大小,單位是
MB
-
MaxBackups 保留的日誌文件數量
-
MaxAge 日誌文件的最長保留時間,單位是天
-
Compress 日誌文件是否需要壓縮
05 總結
本文我們通過在 Gin 構建的應用中,使用 Zap 記錄請求日誌,介紹了 Zap 的使用方式,最後還通過 lumberjack
日誌切割庫進行切割日誌。
更多關於 Zap 的內容,感興趣的讀者朋友們可以閱讀官方文檔或源碼。
參考資料:
-
https://github.com/uber-go/zap
-
https://pkg.go.dev/go.uber.org/zap
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/W9T1HIoXk6czu_W6YC8LHQ