有梦想的鱼
写代码我得再认真点,当我最终放下键盘时,我实在不想仍有太多疑惑

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)
	}
}


posted on 2025-07-27 12:15  yuyuyui  阅读(19)  评论(0)    收藏  举报