美文网首页
go 包:zap日志

go 包:zap日志

作者: 呦丶耍脾气 | 来源:发表于2023-03-29 13:37 被阅读0次

    1.介绍

    Zapuber开源的日志库,支持日志级别分级 、结构化记录,对性能和内存分配做了极致的优化。目前 Star 12.8 源码地址: https://github.com/uber-go/zap

    官方性能测试图

    2.安装

    go get -u gopkg.in/natefinch/lumberjack.v2
    

    3.日志记录器

    Zap提供了两种类型的日志记录器: SugaredLoggerLogger,两者对比如下:

    SugaredLogger : 在性能很好但不是很关键的上下文中使用,它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。与 log15go-kit 一样,SugaredLogger 的结构化日志 api 类型灵活,并接受可变的键值对的数量。

    Logger : 在每一微秒和每一次内存分配都很重要的上下文中,使用Logger。它甚至比SugaredLogger更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。

    4.创建Logger

    4.1 创建Logger几种方式

    Zap中通过调用zap.NewProduction()zap.NewDevelopment()或者zap.Example()可创建一个Logger

    他们创建的Logger,唯一的区别在于它将记录的信息不同。

    使用场景如下:

    • zap.NewProduction() : 在生产环境中使用
    • zap.NewDevelopment() : 在开发环境中使用
    • zap.Example() : 适合用在测试代码中

    4.2 使用示例

    a.代码
    func TestCreateLogger(t *testing.T) {
        // 初始化logger
        logger := zap.NewExample()
        // 使用defer logger.Sync()将缓存同步到文件中。
        defer logger.Sync()
        // 记录日志
        logger.Info("NewExample",
            zap.String("name","张三"),
            zap.Int("age",18),
        )
        productionLogger, _ := zap.NewProduction()
        defer productionLogger.Sync()
        productionLogger.Info("NewProduction",
            zap.String("name","张三"),
            zap.Int("age",18),
        )
        devLogger, _ := zap.NewDevelopment()
        defer devLogger.Sync()
        devLogger.Info("NewDevelopment",
            zap.String("name","张三"),
            zap.Int("age",18),
        )
    }
    
    b. 输出
    === RUN   TestCreateLogger
    {"level":"info","msg":"NewExample","name":"张三","age":18}
    {"level":"info","ts":1624005421.7035909,"caller":"test/zap_test.go:25","msg":"NewProduction","name":"张三","age":18}
    2021-06-18T16:37:01.703+0800    INFO    test/zap_test.go:31    NewDevelopment    {"name": "张三", "age": 18}
    --- PASS: TestCreateLogger (0.00s)
    PASS
    

    zap底层 API 可以设置缓存,所以一般使用defer logger.Sync()将缓存同步到文件中

    4.3 总结

    1. 使用NewProduction()记录日志,默认会记录调用函数信息、日期和时间。
    2. NewExampleNewProduction() 默认都是使用json格式记录日志,而NewDevelopment不是。
    3. 默认情况下日志都会打印到应用程序的控制台界面。
    4. 记录日志时,尽量调用zap.T(key,val)对应的类型方法,这也是zap高性能原因的一部分。

    5.记录日志

    5.1 使用默认记录器(Logger)

    a.代码示例
    // 使用默认记录日志
    func TestRecordLogWithDefault(t *testing.T) {
        // 初始化记录器(使用默认记录器)
        logger := zap.NewExample()
        defer logger.Sync()
        // 记录日志
        logger.Debug("这是debug日志")
        logger.Debug("这是debug日志",zap.String("name","张三"))
        logger.Info("这是info日志",zap.Int("age",18))
        logger.Error("这是error日志",zap.Int("line",130),zap.Error(fmt.Errorf("错误示例")))
        logger.Warn("这是Warn日志")
        // 下面两个都会中断程序
        //logger.Fatal("这是Fatal日志")
        //logger.Panic("这是Panic日志")
    }
    
    b.输出
    === RUN   TestRecordLogWithDefault
    {"level":"debug","msg":"这是debug日志"}
    {"level":"debug","msg":"这是debug日志","name":"张三"}
    {"level":"info","msg":"这是info日志","age":18}
    {"level":"error","msg":"这是error日志","line":130,"error":"错误示例"}
    {"level":"warn","msg":"这是Warn日志"}
    --- PASS: TestRecordLogWithDefault (0.00s)
    

    5.2 使用默认记录器(Sugar)

    a.代码示例
    // 使用Sugar记录器
    func TestRecordLogWithSuage(t *testing.T) {
        // 初始化记录器
        logger := zap.NewExample()
        // 把日志记录器转成Sugar
        sugarLogger := logger.Sugar()
        defer sugarLogger.Sync()
        // 记录日志
        sugarLogger.Debug("这是debug日志 ",zap.String("name","张三"))
        sugarLogger.Debugf("这是Debugf日志 name:%s ","张三")
        sugarLogger.Info("这是info日志",zap.Int("age",18))
        sugarLogger.Infof("这是Infof日志  内容:%v",map[string]string{"爱好":"动漫"})
        sugarLogger.Error("这是error日志",zap.Int("line",130),zap.Error(fmt.Errorf("错误示例")))
        sugarLogger.Errorf("这是Errorf日志,错误信息:%s","错误报告!")
        sugarLogger.Warn("这是Warn日志")
        sugarLogger.Warnf("这是Warnf日志 %v",[]int{1,2,4,5})
        // 下面两个都会中断程序
        //sugarLogger.Fatal("这是Fatal日志")
        //sugarLogger.Panic("这是Panic日志")
    }
    
    b.输出
    === RUN   TestRecordLogWithSuage
    {"level":"debug","msg":"这是debug日志 {name 15 0 张三 <nil>}"}
    {"level":"debug","msg":"这是Debugf日志 name:张三 "}
    {"level":"info","msg":"这是info日志{age 11 18  <nil>}"}
    {"level":"info","msg":"这是Infof日志  内容:map[爱好:动漫]"}
    {"level":"error","msg":"这是error日志{line 11 130  <nil>} {error 26 0  错误示例}"}
    {"level":"error","msg":"这是Errorf日志,错误信息:错误报告!"}
    {"level":"warn","msg":"这是Warn日志"}
    {"level":"warn","msg":"这是Warnf日志 [1 2 4 5]"}
    --- PASS: TestRecordLogWithSuage (0.00s)
    PASS
    

    6.定制Logger

    除了zap.NewProduction()zap.NewDevelopment()zap.Example()还可以通过zap.New(...)创建一个Logger

    6.1 定制一: 输出到文件

    a.代码示例
    func Test2File(t *testing.T) {
        // 指定写入文件
        fileHandle, _ := os.Create("./test.log")
        writeFile := zapcore.AddSync(fileHandle)
        // 设置日志输出格式为JSON (参数复用NewDevelopmentEncoderConfig)
        encoder := zapcore.NewJSONEncoder(zap.NewDevelopmentEncoderConfig())
        // 返回zapcore.Core,并指定记录zap.DebugLevel级别及以上日志
        zcore := zapcore.NewCore(encoder, zapcore.Lock(writeFile), zap.DebugLevel)
        // 创建日志记录器
        logger := zap.New(zcore)
        defer logger.Sync()
        // 记录日志
        logger.Info("输出日志到文件", zap.String("name", "张三"))
    }
    

    6.2 定制二: 同时输入文件和控制台

    // 同时输入到文件和控制台
    func TestPrintFileAndStd(t *testing.T) {
        // 指定写入文件
        fileHandle, _ := os.Create("./test.log")
      // 同时写入文件和控制台 (只修改这一行)
        writeFile := zapcore.NewMultiWriteSyncer(fileHandle,os.Stdout)
        // 设置日志输出格式为JSON (参数复用NewDevelopmentEncoderConfig)
        encoder := zapcore.NewJSONEncoder(zap.NewDevelopmentEncoderConfig())
        // 返回zapcore.Core
        zcore := zapcore.NewCore(encoder, zapcore.Lock(writeFile), zap.DebugLevel)
        // 创建日志记录器
        logger := zap.New(zcore)
        defer logger.Sync()
        // 记录日志
        logger.Info("输出日志到文件", zap.String("name", "张三"))
    }
    

    7.切割日志

    Zap本身不支持文件切割和日志归档,好在开源强大,贡献出Lumberjack,它是一个Go包,用于将日志写入滚动文件。

    7.1 安装Lumberjack

    go get -u github.com/natefinch/lumberjack
    

    7.2 集成到Zap

    a. 代码示例
    // 获取文件切割和归档配置信息
    func getLumberjackConfig() zapcore.WriteSyncer {
        lumberjackLogger := &lumberjack.Logger{
            Filename: "./zap.log",//日志文件
            MaxSize: 1,//单文件最大容量(单位MB)
            MaxBackups: 3,//保留旧文件的最大数量
            MaxAge: 1,// 旧文件最多保存几天
            Compress: false, // 是否压缩/归档旧文件
        }
        return zapcore.AddSync(lumberjackLogger)
    }
    
    // 测试日志切割和归档
    func TestCutAndArchive(t *testing.T) {
        // 设置日志输出格式为JSON (参数复用NewDevelopmentEncoderConfig)
        encoder := zapcore.NewJSONEncoder(zap.NewDevelopmentEncoderConfig())
        core := zapcore.NewCore(encoder, getLumberjackConfig(), zap.DebugLevel)
        sugarLogger := zap.New(core).Sugar()
        defer sugarLogger.Sync()
        // 记录日志
        sugarLogger.Infof("日志内容:%s",strings.Repeat("日志",90000))
    }
    
    b. 效果

    在代码中设置单文件最大容量为1MB,如上图所示当文件超过1MB(527+527 > 1024)时,则分割。

    相关文章

      网友评论

          本文标题:go 包:zap日志

          本文链接:https://www.haomeiwen.com/subject/wkdgrdtx.html