GoLang基于zap日志庫的封裝過程詳解
zap日志封裝
Zap是一個高性能、結(jié)構(gòu)化日志庫,專為Go語言設(shè)計。它由Uber開源,并且在Go社區(qū)中非常受歡迎。它的設(shè)計目標(biāo)是提供一個簡單易用、高效穩(wěn)定、靈活可擴(kuò)展的日志系統(tǒng)。
以下是Zap的一些主要特點:
1.高性能:Zap的性能非常出色,可以在不影響應(yīng)用程序性能的情況下記錄大量的日志。它的性能比其他Go語言的日志庫高出數(shù)倍,這使得它成為高負(fù)載生產(chǎn)環(huán)境中的不錯選擇。
2.結(jié)構(gòu)化日志:Zap支持結(jié)構(gòu)化日志,這意味著你可以在日志中包含結(jié)構(gòu)化數(shù)據(jù),而不是只是簡單的文本。這個功能非常有用,因為它可以讓你更容易地對日志進(jìn)行分析和搜索。
3.可擴(kuò)展:Zap提供了一個靈活的接口,可以讓你輕松地添加自定義的日志輸出器和格式化器。這使得它非常適合在大型項目中使用。
4.模塊化:Zap提供了一個模塊化的設(shè)計,可以讓你選擇僅使用你需要的功能。這使得它非常適合在不同的項目中使用,因為你可以只使用你需要的功能,而不必使用整個庫。
5.安全:Zap使用了一個嚴(yán)格的日志記錄器接口,這可以確保你的應(yīng)用程序的日志記錄不會被惡意軟件篡改或刪除。
實現(xiàn)方式
yaml配置文件
在根目錄下創(chuàng)建一個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,你可以忽略這個tag。在根目錄下創(chuàng)建一個config文件,然后創(chuàng)建一個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 日志留存時間
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 命名方式是因為和zap包重名了,可以根據(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文件中,這個internal的方法僅能在這個core下的文件才可以進(jìn)行訪問,其他文件夾比如service、api、util等文件夾無法訪問,這樣使得這些方法不會泄漏導(dǎo)致程序結(jié)構(gòu)的污染性,我個人也比較喜歡這樣去命名以及去寫代碼。注:下列寫法: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 自定義日志輸出時間格式
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 { // 錯誤級別
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)建一個main.go文件(這個就不多啰嗦了…)
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í)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
Golang實現(xiàn)深拷貝reflect原理示例探究
這篇文章主要為大家介紹了Golang實現(xiàn)reflect深拷貝原理示例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01

