安装
go get -v go.uber.org/zap
zap 格式
zap 有两种格式
- zap.Logger 使用结构体的格式来记录(性能比较高)
- zap.SugaredLogger 使用传统的 printf 的格式来记录(性能相较上一种低)
zap 打印一条日志的大致流程
- 通过 zapcore.Entry 结构体生成一条信息
- 通过 zapcore.Core 的 check 函数检查日志级别,产生一个zapcore.CheckEntry 对象
- 根据日志级别判断是否需要 panic 和 fatal 并退出应用
- 通过zapcore.Option 的设置,zap.AddCaller(),zap.AddStacktrace(1) 或其他自定义的 fields
- 通过 Encoder 为 zapcore.CheckEntry() 提供编码器,通过 EncodeEntry 方法吧 zapcore.Entry 和 zapcore.Fields 转成最后输出格式,json 和 console 转成 buffer.Buffer, memory encode 转成 map
zap 自带的日志记录器
- zap.NewProduction()
- zap.NewDevelopment()
- zap.NewExample()
zap 自定义日志记录器
- 通过 build 创建日志记录器
- 通过 zap.New 创建日志记录器
通过 build 创建
package main
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"io"
"time"
)
var Logger *zap.Logger
func main() {
encoder := zap.Config{
Level: zap.NewAtomicLevel(),
Development: false,
DisableCaller: false,
DisableStacktrace: false,
Encoding: "json",
EncoderConfig: zapcore.EncoderConfig{
MessageKey: "msg",
LevelKey: "level",
TimeKey: "ts",
CallerKey: "file",
StacktraceKey: "stack",
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
encoder.AppendString(t.Format("2006-01-02 15:04:05"))
},
EncodeCaller: zapcore.ShortCallerEncoder,
},
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stdout"},
InitialFields: map[string]interface{}{"url": "localhost"},
}
logger, _ := encoder.Build(zap.AddCaller())
logger.Info("我是一个错误")
}
根据年月日切割日志的方法
这里选择 file-rotatelogs 库
go get -v github.com/lestrrat-go/file-rotatelogs
demo 代码
func getWriter(filename string) io.Writer {
// 生成rotatelogs的Logger 实际生成的文件名 demo.log.YYmmdd
// demo.log是指向最新日志的链接
// 保存7天内的日志,每1小时(整点)分割一次日志
hook, err := rotatelogs.New(
filename+".%Y%m%d", // 没有使用go风格反人类的format格式
rotatelogs.WithLinkName(filename),
rotatelogs.WithMaxAge(time.Hour*24*7),
rotatelogs.WithRotationTime(time.Hour*24),
)
if err != nil {
panic(err)
}
return hook
}
完整代码
通过 zap.New 创建日志记录器
package main
import (
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"io"
"time"
)
var Logger *zap.Logger
func main() {
encoder := zapcore.NewJSONEncoder(zapcore.EncoderConfig{
MessageKey: "msg",
LevelKey: "level",
TimeKey: "ts",
CallerKey: "file",
StacktraceKey: "stack",
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
encoder.AppendString(t.Format("2006-01-02 15:04:05"))
},
EncodeCaller: zapcore.ShortCallerEncoder,
})
highLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl >= zapcore.ErrorLevel
})
lowLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl < zapcore.ErrorLevel
})
hook1 := getWriter("logs/errlogs/err.log")
hook2 := getWriter("logs/infologs/info.log")
core := zapcore.NewTee(
zapcore.NewCore(encoder, zapcore.AddSync(hook1), highLevel),
zapcore.NewCore(encoder, zapcore.AddSync(hook2), lowLevel),
)
logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel))
logger.Info("我是一个错误", zap.String("url", "www.baidu.com"))
}
func getWriter(filename string) io.Writer {
// 生成rotatelogs的Logger 实际生成的文件名 demo.log.YYmmddHH
// demo.log是指向最新日志的链接
// 保存7天内的日志,每24小时(整点)分割一次日志
hook, err := rotatelogs.New(
filename+".%Y%m%d",
rotatelogs.WithLinkName(filename),
rotatelogs.WithMaxAge(time.Hour*24*7),
rotatelogs.WithRotationTime(time.Hour*24),
)
if err != nil {
panic(err)
}
return hook
}
参考
- zap GitHub github.com/uber-go/zap…
- Go 每日一库 github.com/darjun/go-d…
- 夜读大佬的讲解视频 www.bilibili.com/video/BV15b…