GoLang基于zap日志库的封装过程详解
作者:三杯温开水
zap日志封装
Zap是一个高性能、结构化日志库,专为Go语言设计。它由Uber开源,并且在Go社区中非常受欢迎。它的设计目标是提供一个简单易用、高效稳定、灵活可扩展的日志系统。
以下是Zap的一些主要特点:
1.高性能:Zap的性能非常出色,可以在不影响应用程序性能的情况下记录大量的日志。它的性能比其他Go语言的日志库高出数倍,这使得它成为高负载生产环境中的不错选择。
2.结构化日志:Zap支持结构化日志,这意味着你可以在日志中包含结构化数据,而不是只是简单的文本。这个功能非常有用,因为它可以让你更容易地对日志进行分析和搜索。
3.可扩展:Zap提供了一个灵活的接口,可以让你轻松地添加自定义的日志输出器和格式化器。这使得它非常适合在大型项目中使用。
4.模块化:Zap提供了一个模块化的设计,可以让你选择仅使用你需要的功能。这使得它非常适合在不同的项目中使用,因为你可以只使用你需要的功能,而不必使用整个库。
5.安全:Zap使用了一个严格的日志记录器接口,这可以确保你的应用程序的日志记录不会被恶意软件篡改或删除。
实现方式
yaml配置文件
在根目录下创建一个configs
文件夹,然后再创建zap.debug.yaml
# zap logger configuration Zap: Level: 'info' Prefix: 'gin-vue-admin' Format: 'console' Director: 'logs' EncodeLevel: 'LowercaseColorLevelEncoder' StacktraceKey: 'stacktrace' MaxAge: 30 # 默认日志留存默认以天为单位 ShowLine: true LogInConsole: true
放置在全局Config中config.go
我的创建是使用protobuf
快速创建出来的,如果你不是使用protobuf
,你可以忽略这个tag
。在根目录下创建一个config文件,然后创建一个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"` }
创建zap.go
然后再config文件夹再创建zap.go文件,该文件主要是用来将我们配置文件的内容转换成为zap所认识的内容。
type LevelEncoder int // ZapEncodeLevel 根据 EncodeLevel 返回 zapcore.LevelEncoder func (x *Zap) ZapEncodeLevel() zapcore.LevelEncoder { switch { case x.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认) 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 根据字符串转化为 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 } }
创建核心文件core
这里我主要放置一些Initialization
初始化的方法,比如gorm、viper、zap等一些核心的内容。
创建zap.go
在core文件中创建zap.go 文件,该文件主要是初始化自己配置的zap日志,一般会把日志分割、日志存放地、注册到全局等放置在这里,当然为了让代码更加整洁和可阅读性下,我们会对这里封装成为方法。注:
_zap
命名方式是因为和zap包重名了,可以根据自己喜好命名,但是这样的命明也就是仅在该文件下生效,你可以认为这样变成了所谓的私有性
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() 调用日志组件 }
创建私有访问方法
在core文件夹下创建interal文件中,这个internal的方法仅能在这个core下的文件才可以进行访问,其他文件夹比如service、api、util等文件夹无法访问,这样使得这些方法不会泄漏导致程序结构的污染性,我个人也比较喜欢这样去命名以及去写代码。注:
下列写法:core/interal/zap.go ,但是我们调取interal文件夹的方法不需要通过core去调取,直接使用interal进行访问。
core/interal/zap.go
var Zap = new(_zap) type _zap struct{} // GetEncoder 获取 zapcore.Encoder func (z *_zap) GetEncoder() zapcore.Encoder { // 日志的内容格式有 控制台 和 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进行日志分割 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 根据配置文件的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 根据 zapcore.Level 获取 zap.LevelEnablerFunc func (z *_zap) GetLevelPriority(level zapcore.Level) zap.LevelEnablerFunc { switch level { case zapcore.DebugLevel: return func(level zapcore.Level) bool { // 调试级别 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 { // 调试级别 return level == zap.DebugLevel } } }
在main中注册
在根目录下创建一个main.go文件(这个就不多啰嗦了…)
main.go
func main() { core.Zap.Initialization() }
到此这篇关于GoLang基于zap日志库的封装过程详解的文章就介绍到这了,更多相关Go zap日志封装内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!