深入浅析golang zap 日志库使用(含文件切割、分级别存储和全局使用等)


Posted in Javascript onFebruary 19, 2020

日志处理经常有以下几个需求:

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包

深入浅析golang zap 日志库使用(含文件切割、分级别存储和全局使用等)

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 文件目录

深入浅析golang zap 日志库使用(含文件切割、分级别存储和全局使用等)

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 日志库使用(含文件切割、分级别存储和全局使用等),希望对大家有所帮助,也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JQuery 弹出框定位实现方法
Dec 02 Javascript
js判断IE6/IE7/FF的代码[XMLHttpRequest]
Feb 16 Javascript
JS隐藏参数post传值实例
Apr 18 Javascript
详解JavaScript函数绑定
Aug 18 Javascript
angularJS与bootstrap结合实现动态加载弹出提示内容
Oct 16 Javascript
javascript将中国数字格式转换成欧式数字格式的简单实例
Aug 02 Javascript
leaflet的开发入门教程
Nov 17 Javascript
作为老司机使用 React 总结的 11 个经验教训
Apr 08 Javascript
javascript中UMD规范的代码推演
Aug 29 Javascript
React 组件中的 bind(this)示例代码
Sep 16 Javascript
vue 本地服务不能被外部IP访问的完美解决方法
Oct 29 Javascript
解决Vue在封装了Axios后手动刷新页面拦截器无效的问题
Nov 08 Javascript
vue中实现回车键登录功能
Feb 19 #Javascript
Vue中实现回车键切换焦点的方法
Feb 19 #Javascript
整理 node-sass 安装失败的原因及解决办法(小结)
Feb 19 #Javascript
Vue常用的全选/反选的示例代码
Feb 19 #Javascript
详解node和ES6的模块导出与导入
Feb 19 #Javascript
JS实现分页导航效果
Feb 19 #Javascript
vue随机验证码组件的封装实现
Feb 19 #Javascript
You might like
PHP 登录完成后如何跳转上一访问页面
2014/01/14 PHP
destoon出现验证码不显示时的紧急处理方法
2014/08/22 PHP
php实现四舍五入的方法小结
2015/03/03 PHP
jQuery焦点图切换特效插件封装实例
2013/08/18 Javascript
js控制输入框获得和失去焦点时状态显示的方法
2015/01/30 Javascript
基于javascript实现样式清新图片轮播特效
2016/03/30 Javascript
JavaScript函数节流的两种写法
2017/04/07 Javascript
解决vue的变量在settimeout内部效果失效的问题
2018/08/30 Javascript
JavaScript简单实现动态改变HTML内容的方法示例
2018/12/25 Javascript
基于elementUI实现图片预览组件的示例代码
2019/03/31 Javascript
JS实现继承的几种常用方式示例
2019/06/22 Javascript
vue.js中ref及$refs的使用方法解析
2019/10/08 Javascript
vue 修改 data 数据问题并实时显示操作
2020/09/07 Javascript
详解JavaScript 高阶函数
2020/09/14 Javascript
JavaScript this关键字的深入详解
2021/01/14 Javascript
javascript实现点击产生随机图形
2021/01/25 Javascript
介绍Python中的一些高级编程技巧
2015/04/02 Python
Python 中 Virtualenv 和 pip 的简单用法详解
2017/08/18 Python
python基础while循环及if判断的实例讲解
2017/08/25 Python
解决Python 爬虫URL中存在中文或特殊符号无法请求的问题
2018/05/11 Python
Python使用combinations实现排列组合的方法
2018/11/13 Python
Python 中 function(#) (X)格式 和 (#)在Python3.*中的注意事项
2018/11/30 Python
详解Python正则表达式re模块
2019/03/19 Python
python如何读取bin文件并下发串口
2019/07/05 Python
python中时间转换datetime和pd.to_datetime详析
2019/08/11 Python
Python多线程爬取豆瓣影评API接口
2019/10/22 Python
Spring Cloud Feign高级应用实例详解
2019/12/10 Python
Pytest如何使用skip跳过执行测试
2020/08/13 Python
HTML5 实现一个访问本地文件的实例
2012/12/13 HTML / CSS
New Balance英国官方网站:始于1906年,百年慢跑品牌
2016/12/07 全球购物
Nordgreen英国官网:斯堪的纳维亚设计师手表
2018/10/24 全球购物
《假如》教学反思
2014/04/17 职场文书
厉行勤俭节约倡议书
2014/05/16 职场文书
同学聚会通知短信
2015/04/20 职场文书
导游词之苏州寒山寺
2019/12/05 职场文书
JS代码编译器Monaco使用方法
2021/06/11 Javascript