Go日誌管理庫zap

云岛夜川川發表於2024-09-12

一、zap介紹

在許多Go語言專案中,我們需要一個好的日誌記錄器能夠提供下面這些功能:

1.能夠將事件記錄到檔案中,而不是應用程式控制臺。
2.日誌切割-能夠根據檔案大小、時間或間隔等來切割日誌檔案。
3.支援不同的日誌級別。例如INFO,DEBUG,ERROR等。
4.能夠列印基本資訊,如呼叫檔案/函式名和行號,日誌時間等。

二、安裝及使用

2.1 安裝

go get -u go.uber.org/zap

2.2 配置logger日誌記錄器

Zap提供了兩種型別的日誌記錄器—Sugared Logger和Logger,一般使用Logger 。
2.2.1 初始化Logger

func InitLogger() *zap.Logger{
	logger ,_ := zap.NewProduction()
	
	return logger
}

2.2.2 初始化SugaredLogger

//在Logger基礎上呼叫logger.Suger()
func InitLogger() *zap.SugaredLogger{
	logger ,_ := zap.NewProduction()
	
	return logger.Sugar()
}

而初始化logger呼叫的函式可以透過呼叫zap.NewProduction()/zap.NewDevelopment()或者zap.Example()建立一個Logger。區別就是一個是以json的格式返回,一個是以終端標準輸出帶有空格返回。
NewProducts()
image

NewDevelopment()
image

2.3 使用logger進行日誌記錄

使用logger的自帶的方法進行日誌記錄,logger.info(),logger.error().logger.debug等等
這些方法的語法都是

func (log *Logger) MethodXXX(msg string, fields ...Field) 
例如:
logger.info(
	"msg",
	zap.String("msg",v),
	zap.Error(err),

)

完整程式碼

點選檢視程式碼
package main

import (
	"net/http"

	"go.uber.org/zap"
)

var Logger *zap.SugaredLogger
func main() {
	//初始化zap日誌記錄器
	Logger = InitLogger()
	defer Logger.Sync()
	//模擬義務
	Simplefunc("http://www.baidu.com")
	Simplefunc("www.google.com")

}
func InitLogger() *zap.SugaredLogger{
	logger ,_ := zap.NewDevelopment()
	
	return logger.Sugar()
}

func Simplefunc(url string) {
	res,err:=http.Get(url)
	if err!=nil {
		//記錄錯誤日誌
		Logger.Error(
			"http get failed..",
			zap.String("url:",url),
			zap.Error(err),
		)
	}else {
		//使用info記錄成功日誌。
		Logger.Info(
			"get success",
			zap.String("status:",res.Status),
			zap.String("url:",url),
		)
		res.Body.Close()
	}
	
	
}

2.4 自定義logger記錄器

2.4.1 將日誌寫入檔案而不是終端
上述的官方提供的logger生成功能不是那麼強大,專案需要將日誌記錄到檔案和分割 的時候就需要自定義。
zap自定義logger生成器使用zap.New():
func New(core zapcore.Core, options ...Option) *Logger
其中zapcore.Core需要設定三個引數Encoder,WriteSyncer,LogLevel
Encoder:編譯器,通俗說就是輸出日誌是什麼格式,json or 終端格式。

json格式就使用NewJSONEncoder(),並使用預先設定的ProductionEncoderConfig():
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
終端格式就使用NewConsoleEncoder():
zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())

WriteSyncer:將日誌輸出到哪。使用zapcore.AddSync()函式並且將開啟的檔案控制代碼傳進去。

file, _ := os.Create("./test.log")
writeSyncer := zapcore.AddSync(file)

LogLevel:將什麼樣級別的日誌輸出.

程式碼例項:

點選檢視程式碼
//使用自定義的zap logger
func InitLogger() *zap.SugaredLogger{
	//日誌檔案
	logfile, _ :=os.OpenFile("zap_log.log",os.O_APPEND | os.O_CREATE|os.O_RDWR,0666)
	//編碼器
	encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
	//輸出位置
	writeSyncer := zapcore.AddSync(logfile)

	//定義core
	core := zapcore.NewCore(
		encoder,
		writeSyncer,
		zapcore.DebugLevel,
	)

	//建立logger
	logger:= zap.New(core)
	
	return logger.Sugar()
}

2.4.2 若輸出到檔案和終端,只需要更改WriteSyncer引數

點選檢視程式碼
//使用自定義的zap logger
func InitLogger() *zap.SugaredLogger{
	//日誌檔案
	logfile, _ :=os.OpenFile("zap_log.log",os.O_APPEND | os.O_CREATE|os.O_RDWR,0666)
	//編碼器
	encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
	//輸出位置
	// writeSyncer := zapcore.AddSync(logfile)
	//輸出多個位置
	wc := io.MultiWriter(logfile,os.Stdout)
	writeSyncer:= zapcore.AddSync(wc)

	//定義core
	core := zapcore.NewCore(
		encoder,
		writeSyncer,
		zapcore.DebugLevel,
	)

	//建立logger
	logger:= zap.New(core)
	
	return logger.Sugar()
}

效果: ![image](https://img2024.cnblogs.com/blog/3452880/202409/3452880-20240912221329852-1914127797.png)

2.4.3 將輸出的時間轉化

//設定日誌編譯器,什麼型別的日誌
func getEncoder() zapcore.Encoder{
	//encoder配置
	encoderConfig := zap.NewProductionEncoderConfig()
	//設定時間格式為2024-9-1-12.32
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	//json格式
	// jsonencoder := zapcore.NewJSONEncoder(encoderConfig)

	//終端形式
	ConsoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
	return ConsoleEncoder

}

2.4.4 記錄不同級別的日誌
有時候日誌可分為log.erro.log 記錄錯誤級別日誌,;log.success.log記錄成功級別日誌,zapcore.DebugLevel就全記錄。

	core1 := zapcore.NewCore(
		encoder,
		writeSyncer,
		zapcore.DebugLevel,//全記錄
	)
	//錯誤日誌
	core2 :=  zapcore.NewCore(
		encoder,
		getwriteSyncer("log.err.log"),
		zapcore.ErrorLevel,
	)
	c:=zapcore.NewTee(core1,core2)
	logger:= zap.New(c,zap.AddCaller())
	return logger.Sugar()

2.4.5 AddCaller詳細記錄呼叫的程式碼行,AddCallerSkip(1)呼叫鏈很多時直接跳過

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

image

3. 記錄全日誌,錯誤日誌檔案,同步終端,標準時間,記錄程式碼位置的自定義logger程式碼

點選檢視程式碼
//使用自定義的zap logger
func InitLogger() *zap.SugaredLogger{
	
	//編碼器
	encoder := getEncoder()
	//輸出位置
	writeSyncer:= getwriteSyncer("log_all.log")

	//定義core
	core1 := zapcore.NewCore(
		encoder,
		writeSyncer,
		zapcore.DebugLevel,//全記錄
	)
	//錯誤日誌
	core2 :=  zapcore.NewCore(
		encoder,
		getwriteSyncer("log.err.log"),
		zapcore.ErrorLevel,
	)

	//建立單個logger
	// logger:= zap.New(core1,zap.AddCaller(), zap.AddCallerSkip(1)) //AddCaller詳細記錄呼叫的程式碼行,AddCallerSkip(1)呼叫鏈很多時直接跳過
	// return logger.Sugar()

	//建立雙日誌,全日誌和錯誤日誌
	c:=zapcore.NewTee(core1,core2)
	logger:= zap.New(c,zap.AddCaller())
	return logger.Sugar()
}

//設定日誌編譯器,什麼型別的日誌
func getEncoder() zapcore.Encoder{
	//encoder配置
	encoderConfig := zap.NewProductionEncoderConfig()
	//設定時間格式為2024-9-1-12.32
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	//json格式
	// jsonencoder := zapcore.NewJSONEncoder(encoderConfig)

	//終端形式
	ConsoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
	return ConsoleEncoder

}

//設定輸出位置
func getwriteSyncer(logfilename string) zapcore.WriteSyncer {
	//日誌檔案
	logfile, _ :=os.OpenFile(logfilename,os.O_APPEND | os.O_CREATE|os.O_RDWR,0666)

	//只輸出到日誌檔案
	// return zapcore.AddSync(logfile)

	//也輸出到終端
	wc := io.MultiWriter(logfile,os.Stdout)
	return zapcore.AddSync(wc)
}


[========]

[========]

4.使用Lumberjack進行日誌切割歸檔

//設定輸出位置
func getwriteSyncer(logfilename string) zapcore.WriteSyncer {
	//日誌檔案
	// logfile, _ :=os.OpenFile(logfilename,os.O_APPEND | os.O_CREATE|os.O_RDWR,0666)

	//分割日誌
	
	l, _ := rotatelogs.New(
		logfilename+".%Y%m%d%H%M.log",
		rotatelogs.WithMaxAge(30*24*time.Hour),    // 最長儲存30天
		rotatelogs.WithRotationTime(time.Hour*24), // 24小時切割一次
	)

	//也輸出到終端
	wc := io.MultiWriter(l,os.Stdout)
	return zapcore.AddSync(wc)
}

5.上述完整程式碼

點選檢視程式碼
package main

import (
	"io"
	"net/http"
	"os"
	"time"
	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	// "gopkg.in/natefinch/lumberjack.v2"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var Logger *zap.SugaredLogger
func main() {
	//初始化zap日誌記錄器
	Logger = InitLogger()
	defer Logger.Sync()
	//模擬義務
	Simplefunc("http://www.baidu.com")
	Simplefunc("http://www.google.com")

}
//使用自定義的zap logger
func InitLogger() *zap.SugaredLogger{
	
	//編碼器
	encoder := getEncoder()
	//輸出位置
	writeSyncer:= getwriteSyncer("log_all")

	//定義core
	core1 := zapcore.NewCore(
		encoder,
		writeSyncer,
		zapcore.DebugLevel,//全記錄
	)
	//錯誤日誌
	core2 :=  zapcore.NewCore(
		encoder,
		getwriteSyncer("log.err"),
		zapcore.ErrorLevel,
	)

	//建立單個logger
	// logger:= zap.New(core1,zap.AddCaller(), zap.AddCallerSkip(1)) //AddCaller詳細記錄呼叫的程式碼行,AddCallerSkip(1)呼叫鏈很多時直接跳過
	// return logger.Sugar()

	//建立雙日誌,全日誌和錯誤日誌
	c:=zapcore.NewTee(core1,core2)
	logger:= zap.New(c,zap.AddCaller())
	return logger.Sugar()
}

//設定日誌編譯器,什麼型別的日誌
func getEncoder() zapcore.Encoder{
	//encoder配置
	encoderConfig := zap.NewProductionEncoderConfig()
	//設定時間格式為2024-9-1-12.32
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	//json格式
	// jsonencoder := zapcore.NewJSONEncoder(encoderConfig)

	//終端形式
	ConsoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
	return ConsoleEncoder

}

//設定輸出位置
func getwriteSyncer(logfilename string) zapcore.WriteSyncer {
	//日誌檔案
	// logfile, _ :=os.OpenFile(logfilename,os.O_APPEND | os.O_CREATE|os.O_RDWR,0666)

	//分割日誌
	
	l, _ := rotatelogs.New(
		logfilename+".%Y%m%d%H%M.log",
		rotatelogs.WithMaxAge(30*24*time.Hour),    // 最長儲存30天
		rotatelogs.WithRotationTime(time.Hour*24), // 24小時切割一次
	)

	//也輸出到終端
	wc := io.MultiWriter(l,os.Stdout)
	return zapcore.AddSync(wc)
}




func Simplefunc(url string) {
	res,err:=http.Get(url)
	if err!=nil {
		//記錄錯誤日誌
		Logger.Error(
			"http get failed..",
			zap.String("url:",url),
			zap.Error(err),
		)
	}else {
		//使用info記錄成功日誌。
		Logger.Info(
			"get success",
			zap.String("status:",res.Status),
			zap.String("url:",url),
		)
		res.Body.Close()
	}
	
	
}

在gin框架中使用zap日誌記錄器

相關文章