美文网首页
golang zap 日志库使用(含文件切割、分级别存储和全局使

golang zap 日志库使用(含文件切割、分级别存储和全局使

作者: 卡戎li | 来源:发表于2020-02-17 20:39 被阅读0次

    日志处理经常有以下几个需求:
    1、不同级别的日志输出到不同的日志文件中。
    2、日志文件按照文件大小或日期进行切割存储,以避免单一日志文件过大。
    3、日志使用简单方便,一次定义全局使用。

    建议使用使用Uber-go的Zap Logger,大神李文周大博客已经说的非常明确了,请先参考李老师的博客:
    https://www.liwenzhou.com/posts/Go/zap/

    问题二和问题三需要补充描述:

    一、日志按照级别分文件切割存储

    1.1 首先实现两个判断日志等级的interface

    infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
            return lvl >= zapcore.InfoLevel
    })
    
    errorLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
            return lvl >= zapcore.ErrorLevel
    })
    

    1.2 获取 info、error日志文件的io.Writer

    infoWriter := getWriter("./logs/demo_info.log")
    errorWriter := getWriter("./logs/demo_error.log")
    

    文件名可拼接入系统时间

    
    func getWriter(filename string) io.Writer {
        // 生成rotatelogs的Logger 实际生成的文件名 demo.log.YYmmddHH
        // demo.log是指向最新日志的链接
        // 保存7天内的日志,每1小时(整点)分割一次日志
        hook, err := rotatelogs.New(
            strings.Replace(filename, ".log", "", -1)+"-%Y%m%d%H.log", // 没有使用go风格反人类的format格式
            //rotatelogs.WithLinkName(filename),
            //rotatelogs.WithMaxAge(time.Hour*24*7),
            //rotatelogs.WithRotationTime(time.Hour),
        )
    
        if err != nil {
            panic(err)
        }
        return hook
    }
    

    1.3 最后创建具体的Logger

    core := zapcore.NewTee(
            zapcore.NewCore(encoder, zapcore.AddSync(infoWriter), infoLevel),
            zapcore.NewCore(encoder, zapcore.AddSync(errorWriter), errorLevel),
    )
    

    1.4 创建logger

    log := zap.New(core, zap.AddCaller()) 
    errorLogger = log.Sugar()
    

    二、日志定义全局使用

    定义完一个logger 之后,我们希望整个项目可以拿来即用,不需要在每个文件里都进行初始化,我们使用go函数中的静态函数来实现。

    2.1 定义一个logger包

    图片.png

    2.2 定义外部可直接访问的函数

    注意函数首字母要大写

    func Debug(args ...interface{}) {
        errorLogger.Debug(args...)
    }
    
    func Debugf(template string, args ...interface{}) {
        errorLogger.Debugf(template, args...)
    }
    
    func Info(args ...interface{}) {
        errorLogger.Info(args...)
    }
    
    func Infof(template string, args ...interface{}) {
        errorLogger.Infof(template, args...)
    }
    
    func Warn(args ...interface{}) {
        errorLogger.Warn(args...)
    }
    
    func Warnf(template string, args ...interface{}) {
        errorLogger.Warnf(template, args...)
    }
    
    func Error(args ...interface{}) {
        errorLogger.Error(args...)
    }
    
    func Errorf(template string, args ...interface{}) {
        errorLogger.Errorf(template, args...)
    }
    
    func DPanic(args ...interface{}) {
        errorLogger.DPanic(args...)
    }
    
    func DPanicf(template string, args ...interface{}) {
        errorLogger.DPanicf(template, args...)
    }
    

    2.3 在需要使用的地方直接引入logger 包就可以直接使用

    logger.Infof("create token succ , token=%v",   token)
    

    三、源码

    3.1 文件目录

    图片.png

    3.2 lgo.go 源码

    package logger
    
    import (
        rotatelogs "github.com/lestrrat-go/file-rotatelogs"
        "go.uber.org/zap"
        "go.uber.org/zap/zapcore"
        "io"
        "strings"
        "time"
    )
    
    var errorLogger *zap.SugaredLogger
    
    func init(){
        // 设置一些基本日志格式 具体含义还比较好理解,直接看zap源码也不难懂
        encoder := zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
            MessageKey:  "msg",
            LevelKey:    "level",
            EncodeLevel: zapcore.CapitalLevelEncoder,
            TimeKey:     "ts",
            EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
                enc.AppendString(t.Format("2006-01-02 15:04:05"))
            },
            CallerKey:    "file",
            EncodeCaller: zapcore.ShortCallerEncoder,
            EncodeDuration: func(d time.Duration, enc zapcore.PrimitiveArrayEncoder) {
                enc.AppendInt64(int64(d) / 1000000)
            },
        })
    
        // 实现两个判断日志等级的interface
        infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
            return lvl >= zapcore.InfoLevel
        })
    
        errorLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
            return lvl >= zapcore.ErrorLevel
        })
    
        // 获取 info、error日志文件的io.Writer 抽象 getWriter() 在下方实现
        infoWriter := getWriter("./logs/demo_info.log")
        errorWriter := getWriter("./logs/demo_error.log")
    
        // 最后创建具体的Logger
        core := zapcore.NewTee(
            zapcore.NewCore(encoder, zapcore.AddSync(infoWriter), infoLevel),
            zapcore.NewCore(encoder, zapcore.AddSync(errorWriter), errorLevel),
        )
    
        log := zap.New(core, zap.AddCaller()) // 需要传入 zap.AddCaller() 才会显示打日志点的文件名和行数, 有点小坑
        errorLogger = log.Sugar()
    }
    
    func getWriter(filename string) io.Writer {
        // 生成rotatelogs的Logger 实际生成的文件名 demo.log.YYmmddHH
        // demo.log是指向最新日志的链接
        // 保存7天内的日志,每1小时(整点)分割一次日志
        hook, err := rotatelogs.New(
            strings.Replace(filename, ".log", "", -1)+"-%Y%m%d%H.log", // 没有使用go风格反人类的format格式
            //rotatelogs.WithLinkName(filename),
            //rotatelogs.WithMaxAge(time.Hour*24*7),
            //rotatelogs.WithRotationTime(time.Hour),
        )
    
        if err != nil {
            panic(err)
        }
        return hook
    }
    func Debug(args ...interface{}) {
        errorLogger.Debug(args...)
    }
    
    func Debugf(template string, args ...interface{}) {
        errorLogger.Debugf(template, args...)
    }
    
    func Info(args ...interface{}) {
        errorLogger.Info(args...)
    }
    
    func Infof(template string, args ...interface{}) {
        errorLogger.Infof(template, args...)
    }
    
    func Warn(args ...interface{}) {
        errorLogger.Warn(args...)
    }
    
    func Warnf(template string, args ...interface{}) {
        errorLogger.Warnf(template, args...)
    }
    
    func Error(args ...interface{}) {
        errorLogger.Error(args...)
    }
    
    func Errorf(template string, args ...interface{}) {
        errorLogger.Errorf(template, args...)
    }
    
    func DPanic(args ...interface{}) {
        errorLogger.DPanic(args...)
    }
    
    func DPanicf(template string, args ...interface{}) {
        errorLogger.DPanicf(template, args...)
    }
    
    func Panic(args ...interface{}) {
        errorLogger.Panic(args...)
    }
    
    func Panicf(template string, args ...interface{}) {
        errorLogger.Panicf(template, args...)
    }
    
    func Fatal(args ...interface{}) {
        errorLogger.Fatal(args...)
    }
    
    func Fatalf(template string, args ...interface{}) {
        errorLogger.Fatalf(template, args...)
    }
    

    3.3 main 函数使用

    import (
        "flag"
        "goAuth/logger"
        "goAuth/util"
        "os"
    )
    
    
    func main() {
        createAndCheckToken()
        logger.Infof("in main args:%v", os.Args)
    
        logger.Errorf("eerror %v", "error")
        flag.Parse()
        logger.Infof("env is %v", *env)
        config := util.InitConfig( "./config/" + *env + ".conf")
        ip := config["ip"]
        port := config["port"]
        envConfig := config["env"]
        logger.Infof("ip=%v, port=%v, env=%v", ip, port, envConfig)
    }
    

    相关文章

      网友评论

          本文标题:golang zap 日志库使用(含文件切割、分级别存储和全局使

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