目录
前言
一、介绍
二、使用步骤
2.1.配置 zap Logger
2.2 Logger模式
2.3 Sugared Logger模式
三、性能对比
总结
本文介绍非常流行的Uber开源的zap日志库,
下面将介绍zap
提供的两种类型的日志记录器Logger
和Sugared Logger,
同时介绍了如何搭配Lumberjack实现日志的切割和归档,十分实用!
zap
是 uber
开源的 Go
高性能日志库,支持不同的日志级别,
能够打印基本信息等,但不支持日志的分割,
这里我们可以使用 lumberjack
也是 zap
官方推荐用于日志分割,
结合这两个库我们就可以实现
以下功能的日志机制:
DEBUG
, INFO
, WARN
, ERROR
等;zap
提供了两种类型的日志记录器Logger
和Sugared Logger
区别是:
SugaredLogger
。它比其他结构化日志记录包快4-10被,并且支持结构化和printf
风格的日志记录。代码如下(示例):
package main
import (
zap "github.com/openownworld/go-utils/log/zaplog"
)
func main() {
err := zap.InitLoggerFile("./log.ini")
if err != nil {
fmt.Printf("InitLoggerFile error:%v", err)
return
}
zap.Info("test log")
}
配置文件(示例):
#json log key serviceName = testService #时间格式 2022-12-21T15:04:43.697+0800 customTimeEnable = false #日志文件路径 logFileName = ./log/log.log errorFileName = ./log/error.log #MaxBackups和MaxAge 任意达到限制,对应的文件就会被清理,maxSize和maxBackups计算出最大日志总量,在最大天数内不超过日志总量 #最大文件大小 M字节 maxSize = 100 #最多保留30个备份 maxBackups = 30 #最多保留多少天 maxDays = 30 #开启日志压缩 compress = true #日志级别 debug info warn error dpanic panic fatal level = debug #打印堆栈跟踪日志级别 stacktraceLevel = panic #分开写的错误文件级别warn和error errorFileLevel = warn #日志开启关闭 fileLogger = true consoleLogger = true fileLoggerJSON = true consoleLoggerJSON = true #推送日志到socket,暂不支持tcp socketLoggerEnable = false socketLoggerJSON = false socketType = udp socketIP = 127.0.0.1 socketPort = 9990 #动态设置日志级别 levelHttpEnable = false levelHttpApi = /api/v1/log/level levelHttpPort = 9090 #curl -H "Content-Type:application/json" -X PUT --data "{\"level\":\"error\"}" http://localhost:9090/api/v1/log/level
输出结果:
{"level":"info","time":"2023-05-06T11:24:48.184+0800","caller":"zaplog/zaplog.go:123","msg":"DefaultLogger init success [debug]","service":"testService"}
{"level":"error","time":"2023-05-06T11:24:48.185+0800","caller":"zaplog/zaplog.go:123","msg":"DefaultLogger init success [debug]","service":"testService"}
{"level":"info","time":"2023-05-06T11:24:48.186+0800","caller":"zaplog/logger_test.go:13","msg":"test log","service":"testService"}
代码如下(示例):
搭配 lumberjack 进行日志切割归档
package main
import (
"fmt"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
"io"
"os"
"strings"
"time"
)
const (
LogPath = "log"
)
type BackOption struct {
LogPath string
MaxSize int
MaxAge int
MaxBackups int
SkipCaller int
}
type ZapCoreBase struct {
Enc zapcore.Encoder
Ws zapcore.WriteSyncer
Zopts []zap.Option
}
type LogConf struct {
Service string
Path string //日志打印路径
LogName string //日志文件名
Level string
LoggerJSON bool //json格式输出日志
Stdout bool //标准输出、方便
}
type Logger struct {
*zap.SugaredLogger
level zap.AtomicLevel
coreBase *ZapCoreBase
}
func CapitalLevel(level string) zapcore.Level {
trans := []struct {
text string
level zapcore.Level
}{
{"DEBUG", zapcore.DebugLevel},
{"INFO", zapcore.InfoLevel},
{"WARN", zapcore.WarnLevel},
{"ERROR", zapcore.ErrorLevel},
}
for _, tt := range trans {
if strings.ToUpper(level) == tt.text {
return tt.level
}
}
return zapcore.InfoLevel
}
func NewWriteCloser(opts *BackOption, filename string) io.WriteCloser {
wc := &lumberjack.Logger{
Filename: opts.LogPath + "/" + filename, //filePath
MaxSize: opts.MaxSize, //单个日志文件最大大小(以MB为单位)
MaxBackups: opts.MaxBackups, //保留旧文件的最大个数
MaxAge: opts.MaxAge, //保留旧文件的最大天数
Compress: false, //是否压缩
}
return wc
}
// 创建logger
func NewLogger(config *LogConf) *Logger {
var (
defLogger *Logger
defaultLevel = CapitalLevel(config.Level)
opts = &BackOption{
LogPath: config.Path,
MaxSize: 512, //512MB
MaxAge: 10,
MaxBackups: 10,
}
)
if opts.LogPath == "" {
opts.LogPath = LogPath
}
if config.LogName == "" {
config.LogName = "log.log"
}
lmfile := NewWriteCloser(opts, config.LogName)
enConfig := zap.NewProductionEncoderConfig() //生成配置
// 调整时间格式
enConfig.EncodeTime = zapcore.ISO8601TimeEncoder
lvl := zap.NewAtomicLevelAt(defaultLevel)
var writes = []zapcore.WriteSyncer{zapcore.AddSync(lmfile)}
if config.Stdout {
writes = append(writes, zapcore.AddSync(os.Stdout))
}
var encoder = zapcore.NewConsoleEncoder(enConfig)
var logOpts = []zap.Option{zap.AddCaller()}
if config.LoggerJSON { // 按json格式 输出
//
encoder = zapcore.NewJSONEncoder(enConfig)
logOpts = append(logOpts,
zap.Fields(zap.String("service", config.Service)))
}
zCoreBase := &ZapCoreBase{
Enc: encoder,
Ws: zapcore.NewMultiWriteSyncer(writes...),
Zopts: logOpts,
}
core := zapcore.NewCore(
encoder,
zapcore.NewMultiWriteSyncer(writes...), // 打印到控制台和文件
lvl, // 日志级别
)
logger := zap.New(core, zCoreBase.Zopts...)
defLogger = &Logger{
SugaredLogger: logger.Sugar(),
level: lvl,
coreBase: zCoreBase,
}
fmt.Println("create.logger complete...")
return defLogger
}
func main() {
conf := &LogConf{
Service: "testLog",
Path: "./log",
LogName: "log.log",
Level: "debug",
LoggerJSON: true,
}
log := NewLogger(conf)
log.Infof("log init success, time:%v", time.Now())
log.Infow("扩展Json字段的日志打印", "ip", "1.1.1.1")
}
日志文件打印结果:
{"level":"info","ts":"2023-05-06T15:13:46.759+0800","caller":"main/main.go:146","msg":"log init success, time:2023-05-06 15:13:46.759339 +0800 CST m=+0.001190552","service":"testLog"} {"level":"info","ts":"2023-05-06T15:13:46.760+0800","caller":"main/main.go:147","msg":"扩展Json字段的日志打印","service":"testLog","ip":"1.1.1.1"}
Zap是非常快的、结构化的,分日志级别的Go日志库。
为什么选择Uber-go zap
根据Uber-go Zap的文档,它的性能比类似的结构化日志包更好——也比标准库更快。 以下是Zap发布的基准测试信息
记录一条消息和10个字段:
至此,我们总结了如何将Zap日志程序集成到Go应用程序项目中。