一、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()
NewDevelopment()
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()
}
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))
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()
}
}