Go语言学习——zap日志库入门使用

tianqy · · 168 次点击 · 开始浏览    置顶
1.简介<br /> 本文主要是简单介绍下zap库的使用样例,之前看了网上的一些入门资料后,发现有些样例比较简单,结合工程实践,提供一个简单的工程样例;zap是Uber开源的高性能日志库,对zap还不太了解的同学可以先搜下对应的网上资料、有个大概了解。<br /> 2.实现<br /> 本次实践要的实现目标是:<br /> 1)支持不同级别的日志写入不同文件;<br /> 2)支持不同级别的日志写入同一文件;<br /> 3)支持根据环境配置,控制低级别的日志不打印到线上文件;<br /> 4)支持一个logger对象控制多个日志文件,内部根据Enable()实现级别区分;<br /> 在学习zap之前,先参考了网上资料,总结的来说,使用zap生成logger对象涉及到的三要素是 : 文件对象、输出格式以及日志级别,所以会先围绕上面的三要素生成logger对象;由于日志格式化方式各不相同,所以在调用具体输出函数之前,还要对日志内容进行组合;为了方便全局操作,对日志对象封装,抽象出全局日志对象。<br /> 样例实现: ``` package main import ( "bytes" "context" "fmt" "github.com/gin-gonic/gin" "go.uber.org/zap" "go.uber.org/zap/zapcore" "net/http" "os" "os/signal" "runtime" "strconv" "syscall" "time" ) var Mode = "Offline" // 全局日志对象 var GLog *GlobalLogger type GlobalLogger struct { Logger *FileLogger // 服务内部普通日志记录 Request *FileLogger // 服务内部入库日志记录 } // 考虑到要按照指定格式记录日志,所以没有直接对外暴露zap.Logger,而是对zap.Logger封装一下 type FileLogger struct { logger* zap.Logger } func (fl *FileLogger)DEBUG(msg string, fields ...zap.Field) { msg = GenerateLoggerPrefix("DEBUG", fields...) + msg fl.logger.Debug(msg, fields...) } func (fl *FileLogger)INFO(msg string, fields ...zap.Field){ msg = GenerateLoggerPrefix("INFO", fields...) + msg fl.logger.Info(msg, fields...) } func (fl *FileLogger)WARNING(msg string, fields ...zap.Field){ msg = GenerateLoggerPrefix("WARNING", fields...) + msg fl.logger.Warn(msg, fields...) } func (fl *FileLogger)FATAL(msg string, fields ...zap.Field){ msg = GenerateLoggerPrefix("FATAL", fields...) + msg fl.logger.Fatal(msg, fields...) } func (fl *FileLogger)SYNC() { fl.logger.Sync() } var LoggerPrefix = ": TQY " // GenerateLoggerPrefix 生成调试跟踪文件的行前缀,fields是引用传递 func GenerateLoggerPrefix(level string, fields ...zap.Field) string { data := bytes.Buffer{} data.WriteString(level) data.WriteString(LoggerPrefix) data.WriteString("[" + time.Now().Format("2006-01-02 15:04:05") + "] ") a, _, c, _ := runtime.Caller(2) data.WriteString("[" + runtime.FuncForPC(a).Name() + ":" + strconv.Itoa(c) + "] ") qid := "" for _, field := range fields { if field.Key == "Qid" { qid = field.String } } if qid != "" { data.WriteString("[" + qid + "] ") } return data.String() } func GenerateGlobalLogger(dir string) error{ // zap生成logger对象的三要素是 : 文件对象、输出格式化以及日志级别 // step 1 : 生成文件对象 debugFile, err := os.OpenFile(dir + "server.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666) if err != nil { return err } warningFile, err := os.OpenFile(dir + "server.log.wf", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666) if err != nil { return err } requestFile, err := os.OpenFile(dir + "request.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666) if err != nil { return err } // step 2 : 生成输出格式 outputEncoder := GenerateLogFormat() // step 3 : 配置日志级别 debugLevel := zap.LevelEnablerFunc(func(lv zapcore.Level) bool { // 模式判断,线上可以使用gin.Mode()判断 if Mode == "Online" { return lv == zapcore.InfoLevel } return lv <= zapcore.InfoLevel }) warningLevel := zap.LevelEnablerFunc(func(lv zapcore.Level) bool { return lv == zapcore.WarnLevel }) requestLevel := zap.LevelEnablerFunc(func(lv zapcore.Level) bool { return lv == zapcore.InfoLevel }) // step 4 : 创建配置集 coreServer := zapcore.NewTee( zapcore.NewCore(outputEncoder, debugFile, debugLevel), zapcore.NewCore(outputEncoder, warningFile, warningLevel), ) coreRequest := zapcore.NewCore(outputEncoder, requestFile, requestLevel) // step 5 : 创建logger对象 loggerServer := zap.New(coreServer) loggerRequest := zap.New(coreRequest) // step 6 : 初始化全局日志对象 GLog = &GlobalLogger{ Logger:&FileLogger{logger:loggerServer}, Request:&FileLogger{logger:loggerRequest}, } return nil } // 生成日志输出格式 func GenerateLogFormat() zapcore.Encoder { encoderConfig := zapcore.EncoderConfig{ NameKey: "N", CallerKey: "C", MessageKey: "M", StacktraceKey: "S", LineEnding: zapcore.DefaultLineEnding, EncodeLevel: zapcore.CapitalLevelEncoder, EncodeTime: zapcore.ISO8601TimeEncoder, EncodeDuration: zapcore.StringDurationEncoder, } return zapcore.NewConsoleEncoder(encoderConfig) } func main() { if err := GenerateGlobalLogger("./"); err != nil { fmt.Println(err) return } go func() { GLog.Logger.DEBUG("logger debug") GLog.Logger.INFO("logger info") GLog.Logger.WARNING("logger warning") GLog.Request.INFO("request info") }() engine := gin.Default() server := &http.Server{ Addr: ":16889", Handler: engine, } go signalListen(server) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { GLog.Logger.FATAL(fmt.Sprintf("Listen And Serve err: %v", err.Error())) return } } // 信号捕捉,用于缓存flush func signalListen(server *http.Server) { c := make(chan os.Signal) signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) for { <-c GLog.Logger.SYNC() GLog.Request.SYNC() server.Shutdown(context.Background()) } } ```

有疑问加站长微信联系

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:812540095

168 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传