百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

golang高性能日志库zap的使用

ztj100 2025-01-11 18:54 20 浏览 0 评论

摘要

zapUber开发的非常快的、结构化的,分日志级别的Go日志库。根据Uber-go Zap的文档,它的性能比类似的结构化日志包更好,也比标准库更快。具体的性能测试可以去github上看到。

github地址:https://github.com/uber-go/zap

转自:https://www.jianshu.com/p/910b626f67d9

参考:go语言中文文档:www.topgoer.com

创建实例

通过调用zap.NewProduction()/zap.NewDevelopment()或者zap.Example()创建一个Logger。这三个方法的区别在于它将记录的信息不同,参数只能是string类型

//代码
var log *zap.Logger
log = zap.NewExample()
log, _ := zap.NewDevelopment()
log, _ := zap.NewProduction()
log.Debug("This is a DEBUG message")
log.Info("This is an INFO message")

//Example 输出
{"level":"debug","msg":"This is a DEBUG message"}
{"level":"info","msg":"This is an INFO message"}

//Development 输出
2018-10-30T17:14:22.459+0800    DEBUG    development/main.go:7    This is a DEBUG message
2018-10-30T17:14:22.459+0800    INFO    development/main.go:8    This is an INFO message

//Production 输出
{"level":"info","ts":1540891173.3190675,"caller":"production/main.go:8","msg":"This is an INFO message"}
{"level":"info","ts":1540891173.3191047,"caller":"production/main.go:9","msg":"This is an INFO message with fields","region":["us-west"],"id":2}

三种创建方式对比:

  • ExampleProduction使用的是json格式输出,Development使用行的形式输出
  • Development从警告级别向上打印到堆栈中来跟踪始终打印包/文件/行(方法)在行尾添加任何额外字段作为json字符串以大写形式打印级别名称以毫秒为单位打印ISO8601格式的时间戳
  • Production调试级别消息不记录Error,Dpanic级别的记录,会在堆栈中跟踪文件,Warn不会始终将调用者添加到文件中以时间戳格式打印日期以小写形式打印级别名称

格式化输出

zap有两种类型,分别是*zap.Logger*zap.SugaredLogger,它们惟一的区别是,我们通过调用主logger的. Sugar()方法来获取一个SugaredLogger,然后使用SugaredLoggerprintf格式记录语句,例如

var sugarLogger *zap.SugaredLogger

func InitLogger() {
  logger, _ := zap.NewProduction()
    sugarLogger = logger.Sugar()
}

func main() {
    InitLogger()
    defer sugarLogger.Sync()
    sugarLogger.Errorf("Error fetching URL %s : Error = %s", url, err)
}

写入文件

默认情况下日志都会打印到应用程序的console界面,但是为了方便查询,可以将日志写入文件,但是我们不能再使用前面创建实例的3个方法,而是使用zap.New()

package main

import (
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
    "os"
)

var log *zap.Logger
func main() {
    writeSyncer, _ := os.Create("./info.log")                           //日志文件存放目录
    encoderConfig := zap.NewProductionEncoderConfig()                    //指定时间格式
    encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
    encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
    encoder := zapcore.NewConsoleEncoder(encoderConfig)                 //获取编码器,NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
    core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)    //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志
    log = zap.New(core,zap.AddCaller())                                //AddCaller()为显示文件名和行号
    log.Info("hello world")
    log.Error("hello world")
}

日志文件输出结果:

2020-12-16T17:53:30.466+0800    INFO    geth/main.go:18 hello world
2020-12-16T17:53:30.486+0800    ERROR   geth/main.go:19 hello world

同时输出控制台和文件

如果需要同时输出控制台和文件,只需要改造一下zapcore.NewCore即可,示例:

package main

import (
    "github.com/natefinch/lumberjack"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
    "os"
)

var log *zap.Logger

func main() {
    //获取编码器,NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
    encoderConfig := zap.NewProductionEncoderConfig()
    encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder //指定时间格式
    encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
    encoder := zapcore.NewConsoleEncoder(encoderConfig)

    //文件writeSyncer
    fileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
        Filename:   "./info.log", //日志文件存放目录
        MaxSize:    1,            //文件大小限制,单位MB
        MaxBackups: 5,            //最大保留日志文件数量
        MaxAge:     30,           //日志文件保留天数
        Compress:   false,        //是否压缩处理
    })
    fileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(fileWriteSyncer,zapcore.AddSync(os.Stdout)), zapcore.DebugLevel) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志

    log = zap.New(fileCore, zap.AddCaller()) //AddCaller()为显示文件名和行号


    log.Info("hello world")
    log.Error("hello world")
}

文件切割

日志文件会随时间越来越大,为了避免日志文件把硬盘空间占满,需要按条件对日志文件进行切割,zap包本身不提供文件切割的功能,但是可以用zap官方推荐的lumberjack包处理

    //文件writeSyncer
    fileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
        Filename:   "./info.log", //日志文件存放目录,如果文件夹不存在会自动创建
        MaxSize:    1,            //文件大小限制,单位MB
        MaxBackups: 5,            //最大保留日志文件数量
        MaxAge:     30,           //日志文件保留天数
        Compress:   false,        //是否压缩处理
    })

按级别写入文件

为了管理人员的查询方便,一般我们需要将低于error级别的放到info.log,error及以上严重级别日志存放到error.log文件中,我们只需要改造一下zapcore.NewCore方法的第3个参数,然后将文件WriteSyncer拆成infoerror两个即可,示例:

package main

import (
    "github.com/natefinch/lumberjack"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
    "os"
)

var log *zap.Logger

func main() {
    var coreArr []zapcore.Core

    //获取编码器
    encoderConfig := zap.NewProductionEncoderConfig()               //NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
    encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder           //指定时间格式
    encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder    //按级别显示不同颜色,不需要的话取值zapcore.CapitalLevelEncoder就可以了
    //encoderConfig.EncodeCaller = zapcore.FullCallerEncoder        //显示完整文件路径
    encoder := zapcore.NewConsoleEncoder(encoderConfig)

    //日志级别
    highPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool{  //error级别
        return lev >= zap.ErrorLevel
    })
    lowPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {  //info和debug级别,debug级别是最低的
        return lev < zap.ErrorLevel && lev >= zap.DebugLevel
    })

    //info文件writeSyncer
    infoFileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
        Filename:   "./log/info.log",   //日志文件存放目录,如果文件夹不存在会自动创建
        MaxSize:    1,                  //文件大小限制,单位MB
        MaxBackups: 5,                  //最大保留日志文件数量
        MaxAge:     30,                 //日志文件保留天数
        Compress:   false,              //是否压缩处理
    })
    infoFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(infoFileWriteSyncer,zapcore.AddSync(os.Stdout)), lowPriority) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志
    //error文件writeSyncer
    errorFileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
        Filename:   "./log/error.log",      //日志文件存放目录
        MaxSize:    1,                      //文件大小限制,单位MB
        MaxBackups: 5,                      //最大保留日志文件数量
        MaxAge:     30,                     //日志文件保留天数
        Compress:   false,                  //是否压缩处理
    })
    errorFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(errorFileWriteSyncer,zapcore.AddSync(os.Stdout)), highPriority) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志

    coreArr = append(coreArr, infoFileCore)
    coreArr = append(coreArr, errorFileCore)
    log = zap.New(zapcore.NewTee(coreArr...), zap.AddCaller()) //zap.AddCaller()为显示文件名和行号,可省略

    log.Info("hello info")
    log.Debug("hello debug")
    log.Error("hello error")
}

这样修改之后,infodebug级别的日志就存放到info.logerror级别的日志单独放到error.log文件中了

控制台按级别显示颜色

指定编码器的EncodeLevel即可,

    //获取编码器
    encoderConfig := zap.NewProductionEncoderConfig()               //NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
    encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder           //指定时间格式
    encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder    //按级别显示不同颜色,不需要的话取值zapcore.CapitalLevelEncoder就可以了
    encoder := zapcore.NewConsoleEncoder(encoderConfig)

显示文件路径和行号

前面说到要显示文件路径和行号,只需要zap.New方法添加参数zap.AddCaller()即可,如果要显示完整的路径,需要在编码器配置中指定

    //获取编码器
    encoderConfig := zap.NewProductionEncoderConfig()               //NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
    encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder           //指定时间格式
    encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder    //按级别显示不同颜色,不需要的话取值zapcore.CapitalLevelEncoder就可以了
    encoderConfig.EncodeCaller = zapcore.FullCallerEncoder          //显示完整文件路径
    encoder := zapcore.NewConsoleEncoder(encoderConfig)

完整代码

package main

import (
    "github.com/natefinch/lumberjack"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
    "os"
)

var log *zap.Logger

func main() {
    var coreArr []zapcore.Core

    //获取编码器
    encoderConfig := zap.NewProductionEncoderConfig()               //NewJSONEncoder()输出json格式,NewConsoleEncoder()输出普通文本格式
    encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder           //指定时间格式
    encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder    //按级别显示不同颜色,不需要的话取值zapcore.CapitalLevelEncoder就可以了
    //encoderConfig.EncodeCaller = zapcore.FullCallerEncoder        //显示完整文件路径
    encoder := zapcore.NewConsoleEncoder(encoderConfig)

    //日志级别
    highPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool{  //error级别
        return lev >= zap.ErrorLevel
    })
    lowPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {  //info和debug级别,debug级别是最低的
        return lev < zap.ErrorLevel && lev >= zap.DebugLevel
    })

    //info文件writeSyncer
    infoFileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
        Filename:   "./log/info.log",   //日志文件存放目录,如果文件夹不存在会自动创建
        MaxSize:    2,                  //文件大小限制,单位MB
        MaxBackups: 100,                //最大保留日志文件数量
        MaxAge:     30,                 //日志文件保留天数
        Compress:   false,              //是否压缩处理
    })
    infoFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(infoFileWriteSyncer,zapcore.AddSync(os.Stdout)), lowPriority) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志
    //error文件writeSyncer
    errorFileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
        Filename:   "./log/error.log",      //日志文件存放目录
        MaxSize:    1,                      //文件大小限制,单位MB
        MaxBackups: 5,                      //最大保留日志文件数量
        MaxAge:     30,                     //日志文件保留天数
        Compress:   false,                  //是否压缩处理
    })
    errorFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(errorFileWriteSyncer,zapcore.AddSync(os.Stdout)), highPriority) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志

    coreArr = append(coreArr, infoFileCore)
    coreArr = append(coreArr, errorFileCore)
    log = zap.New(zapcore.NewTee(coreArr...), zap.AddCaller()) //zap.AddCaller()为显示文件名和行号,可省略


    log.Info("hello info")
    log.Debug("hello debug")
    log.Error("hello error")
}

相关推荐

Vue 技术栈(全家桶)(vue technology)

Vue技术栈(全家桶)尚硅谷前端研究院第1章:Vue核心Vue简介官网英文官网:https://vuejs.org/中文官网:https://cn.vuejs.org/...

vue 基础- nextTick 的使用场景(vue的nexttick这个方法有什么用)

前言《vue基础》系列是再次回炉vue记的笔记,除了官网那部分知识点外,还会加入自己的一些理解。(里面会有部分和官网相同的文案,有经验的同学择感兴趣的阅读)在开发时,是不是遇到过这样的场景,响应...

vue3 组件初始化流程(vue组件初始化顺序)

学习完成响应式系统后,咋们来看看vue3组件的初始化流程既然是看vue组件的初始化流程,咋们先来创建基本的代码,跑跑流程(在app.vue中写入以下内容,来跑流程)...

vue3优雅的设置element-plus的table自动滚动到底部

场景我是需要在table最后添加一行数据,然后把滚动条滚动到最后。查网上的解决方案都是读取html结构,暴力的去获取,虽能解决问题,但是不喜欢这种打补丁的解决方案,我想着官方应该有相关的定义,于是就去...

Vue3为什么推荐使用ref而不是reactive

为什么推荐使用ref而不是reactivereactive本身具有很大局限性导致使用过程需要额外注意,如果忽视这些问题将对开发造成不小的麻烦;ref更像是vue2时代optionapi的data的替...

9、echarts 在 vue 中怎么引用?(必会)

首先我们初始化一个vue项目,执行vueinitwebpackechart,接着我们进入初始化的项目下。安装echarts,npminstallecharts-S//或...

无所不能,将 Vue 渲染到嵌入式液晶屏

该文章转载自公众号@前端时刻,https://mp.weixin.qq.com/s/WDHW36zhfNFVFVv4jO2vrA前言...

vue-element-admin 增删改查(五)(vue-element-admin怎么用)

此篇幅比较长,涉及到的小知识点也比较多,一定要耐心看完,记住学东西没有耐心可不行!!!一、添加和修改注:添加和编辑用到了同一个组件,也就是此篇文章你能学会如何封装组件及引用组件;第二能学会async和...

最全的 Vue 面试题+详解答案(vue面试题知识点大全)

前言本文整理了...

基于 vue3.0 桌面端朋友圈/登录验证+60s倒计时

今天给大家分享的是Vue3聊天实例中的朋友圈的实现及登录验证和倒计时操作。先上效果图这个是最新开发的vue3.x网页端聊天项目中的朋友圈模块。用到了ElementPlus...

不来看看这些 VUE 的生命周期钩子函数?| 原力计划

作者|huangfuyk责编|王晓曼出品|CSDN博客VUE的生命周期钩子函数:就是指在一个组件从创建到销毁的过程自动执行的函数,包含组件的变化。可以分为:创建、挂载、更新、销毁四个模块...

Vue3.5正式上线,父传子props用法更丝滑简洁

前言Vue3.5在2024-09-03正式上线,目前在Vue官网显最新版本已经是Vue3.5,其中主要包含了几个小改动,我留意到日常最常用的改动就是props了,肯定是用Vue3的人必用的,所以针对性...

Vue 3 生命周期完整指南(vue生命周期及使用)

Vue2和Vue3中的生命周期钩子的工作方式非常相似,我们仍然可以访问相同的钩子,也希望将它们能用于相同的场景。...

救命!这 10 个 Vue3 技巧藏太深了!性能翻倍 + 摸鱼神器全揭秘

前端打工人集合!是不是经常遇到这些崩溃瞬间:Vue3项目越写越卡,组件通信像走迷宫,复杂逻辑写得脑壳疼?别慌!作为在一线摸爬滚打多年的老前端,今天直接甩出10个超实用的Vue3实战技巧,手把...

怎么在 vue 中使用 form 清除校验状态?

在Vue中使用表单验证时,经常需要清除表单的校验状态。下面我将介绍一些方法来清除表单的校验状态。1.使用this.$refs...

取消回复欢迎 发表评论: