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

日志处理经常有以下几个需求:
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)
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,468评论 5 473
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,620评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,427评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,160评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,197评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,334评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,775评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,444评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,628评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,459评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,508评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,210评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,767评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,850评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,076评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,627评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,196评论 2 341

推荐阅读更多精彩内容

  • 写在前面的话 代码中的# > 表示的是输出结果 输入 使用input()函数 用法 注意input函数输出的均是字...
    FlyingLittlePG阅读 2,720评论 0 8
  • 在部署项目时,不可能直接将所有的信息都输出到控制台中,我们可以将这些信息记录到日志文件中,这样不仅方便我们查看程序...
    Wizey阅读 5,582评论 0 15
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 4,951评论 0 6
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 4,915评论 1 13
  • idea 添加注释/** 然后回车 选中代码块 Ctrl+Shift+/ 重点推荐阅读:https://www....
    Helen_Cat阅读 19,684评论 0 37