1.介绍
Zap 是一个高性能、结构化的日志库,广泛用于记录日志以支持调试、监控和系统分析
-
结构化:以键值对形式记录日志,便于后续分析(如 ELK 或 Prometheus)。
-
日志级别:支持 Debug、Info、Warn、Error、DPanic、Panic、Fatal 级别。
-
输出:支持控制台、文件、网络等多种日志输出。
// 下载zap库
go get -u go.uber.org/zap
2.基本使用
初始化设置
- 开发环境:使用 zap.NewDevelopment(),日志更易读。
- 生产环境:使用 zap.NewProduction(),日志更紧凑且适合机器解析。
import "go.uber.org/zap"
func InitLogger(){
// 生产环境配置
logger, err := zap.NewProduction()
if err != nil {
panic(err)
}
}
日志级别并输出时间格式化
- 通过日志配置设置日志级别,例如设置了warn ,那么Debug、Info 就不会输出了
- 设置格式化时间,使用约定
func SetLoggerLevel() {
cfg := zap.NewProductionConfig()
// 设置日志级别
cfg.Level = zap.NewAtomicLevelAt(zap.WarnLevel)
// 设置时间格式化
cfg.EncoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05")
logger, _ := cfg.Build()
// 不会输出Deug 和Info
logger.Debug("这是[Debug]日志")
logger.Info("这是[Info]日志")
// 输出Warn 和 Error
logger.Warn("这是[Warn]日志",
zap.String("Key1", "Value1"),
zap.Int("Key2", 10086),
zap.Duration("Duration", time.Second*100)
)
logger.Error("这是[Error]日志")
}
输出Sugar日志
- Infof, Warnf 在记录日志时可以直接使用格式化字符串和参数,不需要手动构建键值对, 大约10%的性能损失
func SetSugar() {
logger, _ := zap.NewDevelopment()
sl := logger.Sugar()
// 在程序退出时刷新缓冲区
defer logger.Sync()
sl.Infof("开发输出Info日志是: %d \n", 9999)
sl.Warnln("开发输出Warn日志是:", "测试")
}
替换全局日志
func initGlobalLogger() {
cfg := zap.NewDevelopmentConfig()
// 替换时间格式化方式
cfg.EncoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05")
logger, _ := cfg.Build()
zap.ReplaceGlobals(logger)
}
func WriteGlobalLogger() {
zap.L().Debug("全局标准日志")
zap.S().Debug("Sugar日志")
}
日志双写
- 写文件并且写控制台以及其他的多重写入
func WriteLoggerToConsoleAndFile() {
cfg := zap.NewDevelopmentConfig()
cfg.EncoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05")
// 输出console
conWrite := zapcore.NewCore(
zapcore.NewConsoleEncoder(cfg.EncoderConfig),
os.Stdout,
zap.InfoLevel,
)
// 输出文件
file, _ := os.OpenFile("app.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeAppend.Perm())
fileWrite := zapcore.NewCore(
zapcore.NewConsoleEncoder(cfg.EncoderConfig),
file,
zap.InfoLevel,
)
// 合并
core := zapcore.NewTee(conWrite, fileWrite)
logger := zap.New(core, zap.AddCaller())
logger.Info("这个日志将会输出在控制台和写入文件中")
}
日志分片
- 按照时间日期来划分日志文件
type CustomizeWrite struct {
file *os.File
mutex sync.Mutex
currentTime string
}
func (w *CustomizeWrite) Write(b []byte) (length int, err error) {
w.mutex.Lock()
defer w.mutex.Unlock()
// 获取当前时间并且对比写入时时间是否相同,如果相同直接写入
now := time.Now().Format("2001-01-02 15-04-05")
if now == w.currentTime && w.file != nil {
return w.file.Write(b)
}
if w.file != nil {
w.file.Close()
w.file = nil
}
// 创建目录
if err := os.MkdirAll("./logs", 0755); err != nil {
return 0, err
}
name := filepath.Join("logs", now+".log")
file, err := os.OpenFile(name, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeAppend.Perm())
if err != nil {
return 0, err
}
w.file = file
w.currentTime = now
return file.Write(b)
}
- 初始化日志写入
``` go
func SplitLogger() {
cfg := zap.NewDevelopmentConfig()
cfg.EncoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05")
core := zapcore.NewCore(
zapcore.NewConsoleEncoder(cfg.EncoderConfig),
zapcore.NewMultiWriteSyncer(os.Stdout, zapcore.AddSync(&CustomizeWrite{})),
zap.InfoLevel,
)
logger := zap.New(core, zap.AddCaller())
for i := 0; i < 10; i++ {
logger.Sugar().Infof("这是 %d log", i)
time.Sleep(time.Second)
}
}
浙公网安备 33010602011771号