GoLang基于zap日志庫的封裝過程詳解
zap日志封裝
Zap是一個(gè)高性能、結(jié)構(gòu)化日志庫,專為Go語言設(shè)計(jì)。它由Uber開源,并且在Go社區(qū)中非常受歡迎。它的設(shè)計(jì)目標(biāo)是提供一個(gè)簡單易用、高效穩(wěn)定、靈活可擴(kuò)展的日志系統(tǒng)。
以下是Zap的一些主要特點(diǎn):
1.高性能:Zap的性能非常出色,可以在不影響應(yīng)用程序性能的情況下記錄大量的日志。它的性能比其他Go語言的日志庫高出數(shù)倍,這使得它成為高負(fù)載生產(chǎn)環(huán)境中的不錯(cuò)選擇。
2.結(jié)構(gòu)化日志:Zap支持結(jié)構(gòu)化日志,這意味著你可以在日志中包含結(jié)構(gòu)化數(shù)據(jù),而不是只是簡單的文本。這個(gè)功能非常有用,因?yàn)樗梢宰屇愀菀椎貙θ罩具M(jìn)行分析和搜索。
3.可擴(kuò)展:Zap提供了一個(gè)靈活的接口,可以讓你輕松地添加自定義的日志輸出器和格式化器。這使得它非常適合在大型項(xiàng)目中使用。
4.模塊化:Zap提供了一個(gè)模塊化的設(shè)計(jì),可以讓你選擇僅使用你需要的功能。這使得它非常適合在不同的項(xiàng)目中使用,因?yàn)槟憧梢灾皇褂媚阈枰墓δ?,而不必使用整個(gè)庫。
5.安全:Zap使用了一個(gè)嚴(yán)格的日志記錄器接口,這可以確保你的應(yīng)用程序的日志記錄不會被惡意軟件篡改或刪除。
實(shí)現(xiàn)方式
yaml配置文件
在根目錄下創(chuàng)建一個(gè)configs
文件夾,然后再創(chuàng)建zap.debug.yaml
# zap logger configuration Zap: Level: 'info' Prefix: 'gin-vue-admin' Format: 'console' Director: 'logs' EncodeLevel: 'LowercaseColorLevelEncoder' StacktraceKey: 'stacktrace' MaxAge: 30 # 默認(rèn)日志留存默認(rèn)以天為單位 ShowLine: true LogInConsole: true
放置在全局Config中config.go
我的創(chuàng)建是使用protobuf
快速創(chuàng)建出來的,如果你不是使用protobuf
,你可以忽略這個(gè)tag
。在根目錄下創(chuàng)建一個(gè)config文件,然后創(chuàng)建一個(gè)config.go
文件用來存放全局的config。
config.go 文件
type Config struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Zap *Zap `protobuf:"bytes,2,opt,name=Zap,proto3" json:"Zap,omitempty"` } // Zap zap logger config type Zap struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // Level 級別 Level string `protobuf:"bytes,1,opt,name=Level,proto3" json:"Level,omitempty"` // Prefix 日志前綴 Prefix string `protobuf:"bytes,2,opt,name=Prefix,proto3" json:"Prefix,omitempty"` // Format 輸出 Format string `protobuf:"bytes,3,opt,name=Format,proto3" json:"Format,omitempty"` // Director 日志文件夾 Director string `protobuf:"bytes,4,opt,name=Director,proto3" json:"Director,omitempty"` // EncodeLevel 編碼級 EncodeLevel string `protobuf:"bytes,5,opt,name=EncodeLevel,proto3" json:"EncodeLevel,omitempty"` // StacktraceKey 棧名 StacktraceKey string `protobuf:"bytes,6,opt,name=StacktraceKey,proto3" json:"StacktraceKey,omitempty"` // MaxAge 日志留存時(shí)間 MaxAge int64 `protobuf:"varint,7,opt,name=MaxAge,proto3" json:"MaxAge,omitempty"` // ShowLine 顯示行 ShowLine bool `protobuf:"varint,8,opt,name=ShowLine,proto3" json:"ShowLine,omitempty"` // LogInConsole 輸出控制臺 LogInConsole bool `protobuf:"varint,9,opt,name=LogInConsole,proto3" json:"LogInConsole,omitempty"` }
創(chuàng)建zap.go
然后再config文件夾再創(chuàng)建zap.go文件,該文件主要是用來將我們配置文件的內(nèi)容轉(zhuǎn)換成為zap所認(rèn)識的內(nèi)容。
type LevelEncoder int // ZapEncodeLevel 根據(jù) EncodeLevel 返回 zapcore.LevelEncoder func (x *Zap) ZapEncodeLevel() zapcore.LevelEncoder { switch { case x.EncodeLevel == "LowercaseLevelEncoder": // 小寫編碼器(默認(rèn)) return zapcore.LowercaseLevelEncoder case x.EncodeLevel == "LowercaseColorLevelEncoder": // 小寫編碼器帶顏色 return zapcore.LowercaseColorLevelEncoder case x.EncodeLevel == "CapitalLevelEncoder": // 大寫編碼器 return zapcore.CapitalLevelEncoder case x.EncodeLevel == "CapitalColorLevelEncoder": // 大寫編碼器帶顏色 return zapcore.CapitalColorLevelEncoder default: return zapcore.LowercaseLevelEncoder } } // TransportLevel 根據(jù)字符串轉(zhuǎn)化為 zapcore.Level func (x *Zap) TransportLevel() zapcore.Level { x.Level = strings.ToLower(x.Level) switch x.Level { case "debug": return zapcore.DebugLevel case "info": return zapcore.InfoLevel case "warn": return zapcore.WarnLevel case "error": return zapcore.WarnLevel case "dpanic": return zapcore.DPanicLevel case "panic": return zapcore.PanicLevel case "fatal": return zapcore.FatalLevel default: return zapcore.DebugLevel } }
創(chuàng)建核心文件core
這里我主要放置一些Initialization
初始化的方法,比如gorm、viper、zap等一些核心的內(nèi)容。
創(chuàng)建zap.go
在core文件中創(chuàng)建zap.go 文件,該文件主要是初始化自己配置的zap日志,一般會把日志分割、日志存放地、注冊到全局等放置在這里,當(dāng)然為了讓代碼更加整潔和可閱讀性下,我們會對這里封裝成為方法。注:
_zap
命名方式是因?yàn)楹蛕ap包重名了,可以根據(jù)自己喜好命名,但是這樣的命明也就是僅在該文件下生效,你可以認(rèn)為這樣變成了所謂的私有性
core/zap.go
var Zap = new(_zap) type _zap struct{} // Initialization 初始化 func (c *_zap) Initialization() { ok, _ := utils.Directory.PathExists(global.Config.Zap.Director) if !ok { // 判斷是否有 global.Config.Zap.Director 文件夾 fmt.Printf("create %v directory\n", global.Config.Zap.Director) _ = os.Mkdir(global.Config.Zap.Director, os.ModePerm) } cores := internal.Zap.GetZapCores() // 獲取 zap 核心切片 logger := zap.New(zapcore.NewTee(cores...)) // 初始化 zap.Logger if global.Config.Zap.ShowLine { // 判斷是否顯示行 logger = logger.WithOptions(zap.AddCaller()) } zap.ReplaceGlobals(logger) // logger 注冊到全局, 通過 zap.L() 調(diào)用日志組件 }
創(chuàng)建私有訪問方法
在core文件夾下創(chuàng)建interal文件中,這個(gè)internal的方法僅能在這個(gè)core下的文件才可以進(jìn)行訪問,其他文件夾比如service、api、util等文件夾無法訪問,這樣使得這些方法不會泄漏導(dǎo)致程序結(jié)構(gòu)的污染性,我個(gè)人也比較喜歡這樣去命名以及去寫代碼。注:
下列寫法:core/interal/zap.go ,但是我們調(diào)取interal文件夾的方法不需要通過core去調(diào)取,直接使用interal進(jìn)行訪問。
core/interal/zap.go
var Zap = new(_zap) type _zap struct{} // GetEncoder 獲取 zapcore.Encoder func (z *_zap) GetEncoder() zapcore.Encoder { // 日志的內(nèi)容格式有 控制臺 和 json if global.Config.Zap.Format == "json" { return zapcore.NewJSONEncoder(z.GetEncoderConfig()) } return zapcore.NewConsoleEncoder(z.GetEncoderConfig()) } // GetEncoderConfig 獲取zapcore.EncoderConfig func (z *_zap) GetEncoderConfig() zapcore.EncoderConfig { return zapcore.EncoderConfig{ MessageKey: "message", LevelKey: "level", TimeKey: "time", NameKey: "logger", CallerKey: "caller", StacktraceKey: global.Config.Zap.StacktraceKey, LineEnding: zapcore.DefaultLineEnding, EncodeLevel: global.Config.Zap.ZapEncodeLevel(), EncodeTime: z.CustomTimeEncoder, EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.FullCallerEncoder, } } // GetEncoderCore 獲取Encoder的 zapcore.Core func (z *_zap) GetEncoderCore(l zapcore.Level, level zap.LevelEnablerFunc) zapcore.Core { syncer, err := FileRotatelogs.GetWriteSyncer(l.String()) // 使用file-rotatelogs進(jìn)行日志分割 if err != nil { fmt.Printf("Get Write Syncer Failed err:%v", err.Error()) return nil } return zapcore.NewCore(z.GetEncoder(), syncer, level) } // CustomTimeEncoder 自定義日志輸出時(shí)間格式 func (z *_zap) CustomTimeEncoder(t time.Time, encoder zapcore.PrimitiveArrayEncoder) { encoder.AppendString(global.Config.Zap.Prefix + " " + t.Format("2006-01-02 15:04:05.000")) } // GetZapCores 根據(jù)配置文件的Level獲取 []zapcore.Core func (z *_zap) GetZapCores() []zapcore.Core { cores := make([]zapcore.Core, 0, 7) for level := global.Config.Zap.TransportLevel(); level <= zapcore.FatalLevel; level++ { cores = append(cores, z.GetEncoderCore(level, z.GetLevelPriority(level))) } return cores } // GetLevelPriority 根據(jù) zapcore.Level 獲取 zap.LevelEnablerFunc func (z *_zap) GetLevelPriority(level zapcore.Level) zap.LevelEnablerFunc { switch level { case zapcore.DebugLevel: return func(level zapcore.Level) bool { // 調(diào)試級別 return level == zap.DebugLevel } case zapcore.InfoLevel: return func(level zapcore.Level) bool { // 日志級別 return level == zap.InfoLevel } case zapcore.WarnLevel: return func(level zapcore.Level) bool { // 警告級別 return level == zap.WarnLevel } case zapcore.ErrorLevel: return func(level zapcore.Level) bool { // 錯(cuò)誤級別 return level == zap.ErrorLevel } case zapcore.DPanicLevel: return func(level zapcore.Level) bool { // dpanic級別 return level == zap.DPanicLevel } case zapcore.PanicLevel: return func(level zapcore.Level) bool { // panic級別 return level == zap.PanicLevel } case zapcore.FatalLevel: return func(level zapcore.Level) bool { // 終止級別 return level == zap.FatalLevel } default: return func(level zapcore.Level) bool { // 調(diào)試級別 return level == zap.DebugLevel } } }
在main中注冊
在根目錄下創(chuàng)建一個(gè)main.go文件(這個(gè)就不多啰嗦了…)
main.go
func main() { core.Zap.Initialization() }
到此這篇關(guān)于GoLang基于zap日志庫的封裝過程詳解的文章就介紹到這了,更多相關(guān)Go zap日志封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang中set數(shù)據(jù)結(jié)構(gòu)的使用示例
本文主要介紹了golang中set數(shù)據(jù)結(jié)構(gòu)的使用示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03Golang實(shí)現(xiàn)深拷貝reflect原理示例探究
這篇文章主要為大家介紹了Golang實(shí)現(xiàn)reflect深拷貝原理示例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01