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

golang高性能日志库zap的使用

ztj100 2025-01-11 18:54 25 浏览 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")
}

相关推荐

再说圆的面积-蒙特卡洛(蒙特卡洛方法求圆周率的matlab程序)

在微积分-圆的面积和周长(1)介绍微积分方法求解圆的面积,本文使用蒙特卡洛方法求解圆面积。...

python编程:如何使用python代码绘制出哪些常见的机器学习图像?

专栏推荐...

python创建分类器小结(pytorch分类数据集创建)

简介:分类是指利用数据的特性将其分成若干类型的过程。监督学习分类器就是用带标记的训练数据建立一个模型,然后对未知数据进行分类。...

matplotlib——绘制散点图(matplotlib散点图颜色和图例)

绘制散点图不同条件(维度)之间的内在关联关系观察数据的离散聚合程度...

python实现实时绘制数据(python如何绘制)

方法一importmatplotlib.pyplotaspltimportnumpyasnpimporttimefrommathimport*plt.ion()#...

简单学Python——matplotlib库3——绘制散点图

前面我们学习了用matplotlib绘制折线图,今天我们学习绘制散点图。其实简单的散点图与折线图的语法基本相同,只是作图函数由plot()变成了scatter()。下面就绘制一个散点图:import...

数据分析-相关性分析可视化(相关性分析数据处理)

前面介绍了相关性分析的原理、流程和常用的皮尔逊相关系数和斯皮尔曼相关系数,具体可以参考...

免费Python机器学习课程一:线性回归算法

学习线性回归的概念并从头开始在python中开发完整的线性回归算法最基本的机器学习算法必须是具有单个变量的线性回归算法。如今,可用的高级机器学习算法,库和技术如此之多,以至于线性回归似乎并不重要。但是...

用Python进行机器学习(2)之逻辑回归

前面介绍了线性回归,本次介绍的是逻辑回归。逻辑回归虽然名字里面带有“回归”两个字,但是它是一种分类算法,通常用于解决二分类问题,比如某个邮件是否是广告邮件,比如某个评价是否为正向的评价。逻辑回归也可以...

【Python机器学习系列】拟合和回归傻傻分不清?一文带你彻底搞懂

一、拟合和回归的区别拟合...

推荐2个十分好用的pandas数据探索分析神器

作者:俊欣来源:关于数据分析与可视化...

向量数据库:解锁大模型记忆的关键!选型指南+实战案例全解析

本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在...

用Python进行机器学习(11)-主成分分析PCA

我们在机器学习中有时候需要处理很多个参数,但是这些参数有时候彼此之间是有着各种关系的,这个时候我们就会想:是否可以找到一种方式来降低参数的个数呢?这就是今天我们要介绍的主成分分析,英文是Princip...

神经网络基础深度解析:从感知机到反向传播

本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在...

Python实现基于机器学习的RFM模型

CDA数据分析师出品作者:CDALevelⅠ持证人岗位:数据分析师行业:大数据...

取消回复欢迎 发表评论: