# Day15 Gin框架之zap日志库

# 日志记录器介绍

一个好的日志记录器应具备这些功能:

  • 能够将事件记录到文件中,而不仅仅是应用程序控制台;
  • 日志切割,如根据大小、时间或时间间隔等切割日志文件;
  • 支持不同的日志级别,如INFO,DEBUG,ERROR等;
  • 能够打印基本信息,如调用文件/函数名和行号,日志时间等;

# 内置日志库 Logger

  • 仅支持配置日志输出io.Writer,无日志分级、切割、格式化等能力
package main

import (
	"log"
	"os"
)

func SetupLogger() {
	logFileLocation, _ := os.OpenFile("./default.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	log.SetOutput(logFileLocation)
}

func main() {
	SetupLogger()
	log.Println("Fetch url err:", "www.baidu.com")
}

# 开源日志库 Zap

uber-go 开源,基本支持日志记录器介绍

  • 安装依赖
go get -u go.uber.org/zap
  • 基本使用
package main

import "go.uber.org/zap"

func main() {

	// logger := zap.NewExample()
	// logger, err := zap.NewDevelopment()
	logger, err := zap.NewProduction() // 用这个就行,输出json更完善
	if err != nil {
		panic(err)
	}

	var uid int64 = 10000111
	married := false
	name := "linda"
	data := []int{1001, 1002, 1003}
	// 固定类型-性能输出; 固定json格式, 兼容EFK等
	logger.Info("日志信息",
		zap.Int64("uid", uid),
		zap.Bool("married", married),
		zap.String("name", name),
		zap.Ints("data", data),
	)
}

/*
1. 性能强悍
2. 格式化输出
*/
  • 格式说明
func (log *Logger) Info(msg string, fields ...zapcore.Field)

1. 日志级别 Debug、Info、Warn、Error、DPanic、Panic、Fatal
2. msg 定义具体的业务场景
3. zapcore.Field 一组键值对参数,如 zap.Int64("uid", uid)
  • 结果输出
{"level":"info","ts":1670493677.338023,"caller":"day15/main.go:19","msg":"日志信息","uid":10000111,"married":false,"name":"linda","data":[1001,1002,1003]}
{"level":"info","ts":1670493678.961177,"caller":"day15/main.go:19","msg":"日志信息","uid":10000111,"married":false,"name":"linda","data":[1001,1002,1003]}

# 定制日志库 Zap

  • 基本定制 三步走
package main

import (
	"os"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {
	// 1. Encoder 编码器(以怎样格式写入日志),如 json 格式
	encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
	// encoder := zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())  // 文本格式

	// 2. WriterSyncer 指定日志将写到哪里去,如 写到文件
	logFileLocation, _ := os.OpenFile("./zap.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	writeSyncer := zapcore.AddSync(logFileLocation)

	// 3. Log Level 哪种级别的日志将被写入
	core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)

	// 最终汇总为core
	logger := zap.New(core)

	var uid int64 = 10000111
	logger.Debug("日志级别", zap.Int64("uid", uid))
	logger.Info("日志级别", zap.Int64("uid", uid))
}

/*
{"level":"debug","ts":1670494920.1061609,"msg":"日志级别","uid":10000111}
{"level":"info","ts":1670494920.106252,"msg":"日志级别","uid":10000111}
*/

# 精细化配置 Zap

package main

import (
	"io"
	"os"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {
	// 1. Encoder
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder   // 时间格式 2022-12-08T18:24:07.979+0800
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // 大写 "level":"INFO"
	encoderConfig.TimeKey = "timestamp"                     // "timestamp":"2022-12-08T18:41:35.596+0800"
	encoder := zapcore.NewJSONEncoder(encoderConfig)

	// 2. WriterSyncer 同时输出到文件和控制台
	logFileLocation, _ := os.OpenFile("./zap.app.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	writeSyncer := zapcore.AddSync(io.MultiWriter(logFileLocation, os.Stdout))

	// 汇总配置1
	core1 := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)

	// 汇总配置2 将err日志单独输出到文件
	errFileLocation, _ := os.OpenFile("./zap.err.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	core2 := zapcore.NewCore(encoder, zapcore.AddSync(errFileLocation), zap.ErrorLevel)

	// 统一汇总
	core := zapcore.NewTee(core1, core2)
	// 调用函数信息 如 "caller":"day15/main.go:27", zap.AddCallerSkip(1)用于额外封装一层场景
	logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))

	var uid int64 = 10000111
	logger.Debug("日志级别", zap.Int64("uid", uid))
	logger.Info("日志级别", zap.Int64("uid", uid))
	logger.Error("日志级别", zap.Int64("uid", uid))
}
  • 定制输出格式,如时间Key名称和格式等
  • Error日志输出到单独文件,便于排错;
  • Debug级别日志可以同时输出到指定文件和控制台

# 日志切割 Lumberjack

  • Zap本身不支持切割归档日志文件

  • 安装依赖

go get gopkg.in/natefinch/lumberjack.v2
  • 基本使用
package main

import (
	"io"
	"os"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

func main() {
	encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
	// 输出到 lumberJackLogger 
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "./zap.app.log", // 日志文件的位置
		MaxSize:    1,               // 在进行切割之前,日志文件的最大大小(以MB为单位)
		MaxBackups: 5,               // 保留旧文件的最大个数
		MaxAge:     30,              // 保留旧文件的最大天数
		Compress:   false,           // 是否压缩/归档旧文件
	}
	writeSyncer := zapcore.AddSync(io.MultiWriter(lumberJackLogger, os.Stdout))
    core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)

	logger := zap.New(core, zap.AddCaller())

	var uid int64 = 10000111
	for {
		logger.Debug("日志级别", zap.Int64("uid", uid))
	}
}
  • 实测结果 只保留5个

上次更新: 12/12/2022, 8:55:46 PM