版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第GO語(yǔ)言框架快速集成日志模塊的操作方法目錄前言zap包的集成簡(jiǎn)介最基礎(chǔ)的使用定制化進(jìn)階封裝
前言
在我們的日常開(kāi)發(fā)中,日志模塊永遠(yuǎn)是最基礎(chǔ)且最重要的一個(gè)模塊,它可以有效的幫我們發(fā)現(xiàn)問(wèn)題,定位問(wèn)題,最后去解決問(wèn)題;
zap包的集成
簡(jiǎn)介
zap是一個(gè)可以在go項(xiàng)目中進(jìn)行快速,結(jié)構(gòu)化且分級(jí)的日志記錄包,gitstar數(shù)高達(dá)16.3k,Git項(xiàng)目地址,在各大公司項(xiàng)目中被廣泛使用;
最基礎(chǔ)的使用
packagemain
import(
"/zap"
"time"
funcmain(){
logger,_:=zap.NewProduction()
deferlogger.Sync()
logger.Info("loginfomsg",
zap.String("name","掘金"),
zap.Int("num",3),
zap.Duration("timer",time.Minute),
}
{"level":"info","ts":1657600159.826612,"caller":"log/main.go:11","msg":"loginfomsg","name":"腳本","num":3,"timer":60}
{"level":"warn","ts":1657600159.8266969,"caller":"log/main.go:16","msg":"thisiserrmsg","msg":"codeerr"}
可以看到上面就是打印出來(lái)的log,當(dāng)然這是用的默認(rèn)配置,所以格式和輸出可能不太符合我們的要求,我們可以自己修改配置來(lái)完成定制化log;
定制化
//NewProductionbuildsasensibleproductionLoggerthatwritesInfoLeveland
//abovelogstostandarderrorasJSON.
//It'sashortcutforNewProductionConfig().Build(...Option).
funcNewProduction(options...Option)(*Logger,error){
returnNewProductionConfig().Build(options...)
}
可以看到生成log的方法其實(shí)就是用config和build來(lái)構(gòu)造一個(gè)記錄器,我們?cè)囋囎远x一下;
packagemain
import(
"/zap"
"/zap/zapcore"
"time"
funcmain(){
conf:=zap.NewProductionConfig()
//可以把輸出方式改為控制臺(tái)編碼,更容易閱讀
conf.Encoding="console"
//時(shí)間格式自定義
conf.EncoderConfig.EncodeTime=func(ttime.Time,enczapcore.PrimitiveArrayEncoder){
enc.AppendString("["+t.Format("2006-01-0215:04:05")+"]")
//打印路徑自定義
conf.EncoderConfig.EncodeCaller=func(callerzapcore.EntryCaller,encoderzapcore.PrimitiveArrayEncoder){
encoder.AppendString("["+caller.TrimmedPath()+"]")
//級(jí)別顯示自定義
conf.EncoderConfig.EncodeLevel=func(levelzapcore.Level,encoderzapcore.PrimitiveArrayEncoder){
encoder.AppendString("["+level.String()+"]")
logger,_:=conf.Build()
logger.Info("servicestart")
logger.Info("infomsg",
zap.String("name","掘金"),
zap.Int("num",3),
zap.Duration("timer",time.Minute),
}
[2025-07-1214:57:18][info][log/main.go:28]servicestart
[2025-07-1214:57:18][info][log/main.go:30]infomsg{"name":"掘金","num":3,"timer":60}
這種日志一般大家看起來(lái)就比較舒服了,特別是打印json結(jié)構(gòu)的話(huà)可以直接復(fù)制解析器里面去看,沒(méi)有json編碼的各種轉(zhuǎn)義;
zap包還是很靈活的,基本上配置參數(shù)都支持自定義(輸出鍵名,格式等等),大家可以按需配置使用;
//AnEncoderConfigallowsuserstoconfiguretheconcreteencoderssuppliedby
//zapcore.
typeEncoderConfigstruct{
//Setthekeysusedforeachlogentry.Ifanykeyisempty,thatportion
//oftheentryisomitted.
MessageKeystring`json:"messageKey"yaml:"messageKey"`
LevelKeystring`json:"levelKey"yaml:"levelKey"`
TimeKeystring`json:"timeKey"yaml:"timeKey"`
NameKeystring`json:"nameKey"yaml:"nameKey"`
CallerKeystring`json:"callerKey"yaml:"callerKey"`
FunctionKeystring`json:"functionKey"yaml:"functionKey"`
StacktraceKeystring`json:"stacktraceKey"yaml:"stacktraceKey"`
LineEndingstring`json:"lineEnding"yaml:"lineEnding"`
//Configuretheprimitiverepresentationsofcommoncomplextypes.For
//example,someusersmaywantalltime.Timesserializedasfloating-point
//secondssinceepoch,whileothersmaypreferISO8601strings.
EncodeLevelLevelEncoder`json:"levelEncoder"yaml:"levelEncoder"`
EncodeTimeTimeEncoder`json:"timeEncoder"yaml:"timeEncoder"`
EncodeDurationDurationEncoder`json:"durationEncoder"yaml:"durationEncoder"`
EncodeCallerCallerEncoder`json:"callerEncoder"yaml:"callerEncoder"`
//Unliketheotherprimitivetypeencoders,EncodeNameisoptional.The
//zerovaluefallsbacktoFullNameEncoder.
EncodeNameNameEncoder`json:"nameEncoder"yaml:"nameEncoder"`
//Configuresthefieldseparatorusedbytheconsoleencoder.Defaults
//totab.
ConsoleSeparatorstring`json:"consoleSeparator"yaml:"consoleSeparator"`
}
進(jìn)階封裝
項(xiàng)目里面生產(chǎn)環(huán)境為了方便收集日志可能都比較喜歡用json,開(kāi)發(fā)環(huán)境中大家又都比較喜歡console方便調(diào)試,還有比如希望接口/服務(wù)日志帶上屬于自己的唯一請(qǐng)求標(biāo)識(shí)這種,以及對(duì)日志進(jìn)行分類(lèi)保存等等,就需要對(duì)zap包進(jìn)行再一次的封裝;
下面是我自己封裝的log包代碼,可以很方便的解決上面的問(wèn)題,大家可以當(dāng)做參考;
index.go記錄器初始化,根據(jù)配置選擇編碼輸出方式及日志文件保存邏輯,以及一些自己自定義的輸出標(biāo)準(zhǔn);
packagelogging
import(
"/zap"
"/zap/buffer"
"/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
"os"
"path"
"strings"
type(
Confstruct{
Pathstring//日志路徑
Encoderstring//編碼器選擇
logItemstruct{
FileNamestring
Levelzap.LevelEnablerFunc
Encoderinterface{
Config()zapcore.Encoder
WithKey(keystring)Encoder
WithField(key,valstring)Encoder
Debug(msgstring)
Debugf(formatstring,v...interface{})
Info(msgstring)
Infof(formatstring,v...interface{})
Warn(msgstring)
Warnf(formatstring,v...interface{})
Error(msgstring)
Errorf(formatstring,v...interface{})
Fatal(msgstring)
Fatalf(formatstring,v...interface{})
var(
maxSize=200//每個(gè)日志文件最大尺寸200M
maxBackups=20//日志文件最多保存20個(gè)備份
maxAge=30//保留最大天數(shù)
_logger*zap.Logger
_pool=buffer.NewPool()
cConf
ConsoleEncoder="console"http://控制臺(tái)輸出
JsonEncoder="json"http://json輸出
//Init初始化日志.
funcInit(confConf){
c=conf
prefix,suffix:=getFileSuffixPrefix(c.Path)
infoPath:=path.Join(prefix+".info"+suffix)
errPath:=path.Join(prefix+".err"+suffix)
items:=[]logItem{
FileName:infoPath,
Level:func(levelzapcore.Level)bool{
returnlevel=zap.InfoLevel
FileName:errPath,
Level:func(levelzapcore.Level)bool{
returnlevelzap.InfoLevel
NewLogger(items)
//NewLogger日志.
funcNewLogger(items[]logItem){
var(
cfgzapcore.Encoder
cores[]zapcore.Core
switchc.Encoder{
caseJsonEncoder:
cfg=NewJsonLog().Config()
caseConsoleEncoder:
cfg=NewConsoleLog().Config()
default:
cfg=NewConsoleLog().Config()
for_,v:=rangeitems{
hook:=lumberjack.Logger{
Filename:v.FileName,
MaxSize:maxSize,//每個(gè)日志文件保存的最大尺寸單位:M
MaxBackups:maxBackups,//日志文件最多保存多少個(gè)備份
MaxAge:maxAge,//文件最多保存多少天
Compress:true,//是否壓縮
LocalTime:true,//備份文件名本地/UTC時(shí)間
core:=zapcore.NewCore(
cfg,//編碼器配置;
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout),zapcore.AddSync(hook)),//打印到控制臺(tái)和文件
v.Level,//日志級(jí)別
cores=append(cores,core)
//開(kāi)啟開(kāi)發(fā)模式,堆棧跟蹤
caller:=zap.AddCaller()
//開(kāi)發(fā)模式
development:=zap.Development()
//二次封裝
skip:=zap.AddCallerSkip(1)
//構(gòu)造日志
_logger=zap.New(zapcore.NewTee(cores...),caller,development,skip)
return
//GetEncoder獲取自定義編碼器.
funcGetEncoder()Encoder{
switchc.Encoder{
caseJsonEncoder:
returnNewJsonLog()
caseConsoleEncoder:
returnNewConsoleLog()
default:
returnNewConsoleLog()
//GetLogger獲取日志記錄器.
funcGetLogger()*zap.Logger{
return_logger
//getFileSuffixPrefix文件路徑切割
funcgetFileSuffixPrefix(fileNamestring)(prefix,suffixstring){
paths,_:=path.Split(fileName)
base:=path.Base(fileName)
suffix=path.Ext(fileName)
prefix=strings.TrimSuffix(base,suffix)
prefix=path.Join(paths,prefix)
return
//getFilePath自定義獲取文件路徑.
funcgetFilePath(eczapcore.EntryCaller)string{
if!ec.Defined{
return"undefined"
buf:=_pool.Get()
buf.AppendString(ec.Function)
buf.AppendByte(':')
buf.AppendInt(int64(ec.Line))
caller:=buf.String()
buf.Free()
returncaller
}
console.go控制臺(tái)編碼輸出,支持自定義;
packagelogging
import(
"fmt"
"/zap"
"/zap/zapcore"
"time"
typeConsoleLogstruct{
valstring
funcNewConsoleLog()Encoder{
returnnew(ConsoleLog)
//Config自定義配置.
func(slf*ConsoleLog)Config()zapcore.Encoder{
var(
cfg=zap.NewProductionEncoderConfig()
//時(shí)間格式自定義
cfg.EncodeTime=func(ttime.Time,enczapcore.PrimitiveArrayEncoder){
enc.AppendString("["+t.Format("2006-01-0215:04:05")+"]")
//打印路徑自定義
cfg.EncodeCaller=func(callerzapcore.EntryCaller,encoderzapcore.PrimitiveArrayEncoder){
encoder.AppendString("["+getFilePath(caller)+"]")
//級(jí)別顯示自定義
cfg.EncodeLevel=func(levelzapcore.Level,encoderzapcore.PrimitiveArrayEncoder){
encoder.AppendString("["+level.String()+"]")
returnzapcore.NewConsoleEncoder(cfg)
//WithKey添加單個(gè)鍵.
func(slf*ConsoleLog)WithKey(keystring)Encoder{
slf.val=slf.val+"["+key+"]"
returnslf
//WithField添加字段.
func(slf*ConsoleLog)WithField(key,valstring)Encoder{
slf.val=slf.val+fmt.Sprintf("[%s:%s]",key,val)
returnslf
func(slf*ConsoleLog)Debug(msgstring){
_logger.Debug(slf.val+msg)
func(slf*ConsoleLog)Debugf(formatstring,v...interface{}){
_logger.Debug(fmt.Sprintf(slf.val+format,v...))
func(slf*ConsoleLog)Info(msgstring){
_logger.Info(slf.val+msg)
func(slf*ConsoleLog)Infof(formatstring,v...interface{}){
_logger.Info(fmt.Sprintf(slf.val+format,v...))
func(slf*ConsoleLog)Warn(msgstring){
_logger.Warn(slf.val+msg)
func(slf*ConsoleLog)Warnf(formatstring,v...interface{}){
_logger.Warn(fmt.Sprintf(slf.val+format,v...))
func(slf*ConsoleLog)Error(msgstring){
_logger.Error(slf.val+msg)
func(slf*ConsoleLog)Errorf(formatstring,v...interface{}){
_logger.Error(fmt.Sprintf(slf.val+format,v...))
func(slf*ConsoleLog)Fatal(msgstring){
_logger.Fatal(slf.val+msg)
func(slf*ConsoleLog)Fatalf(formatstring,v...interface{}){
_logger.Fatal(fmt.Sprintf(slf.val+format,v...))
}
json.gojson編碼輸出,支持自定義;
packagelogging
import(
"fmt"
"/zap/zapcore"
"time"
"/zap"
typeJsonLogstruct{
fields[]zap.Field
valstring
//NewJsonLog自定義添加logfield.
funcNewJsonLog()Encoder{
returnJsonLog{fields:make([]zap.Field,0)}
//Config自定義配置.
func(slf*JsonLog)Config()zapcore.Encoder{
var(
cfg=zap.NewProductionEncoderConfig()
//時(shí)間格式自定義
cfg.EncodeTime=func(ttime.Time,enczapcore.PrimitiveArrayEncoder){
enc.AppendString(t.Format("2006-01-0215:04:05"))
//打印路徑自定義
cfg.EncodeCaller=func(callerzapcore.EntryCaller,encoderzapcore.PrimitiveArrayEncoder){
encoder.AppendString(getFilePath(caller))
//級(jí)別顯示自定義
cfg.EncodeLevel=func(levelzapcore.Level,encoderzapcore.PrimitiveArrayEncoder){
encoder.AppendString(level.String())
returnzapcore.NewJSONEncoder(cfg)
//WithKey添加單個(gè)鍵.
func(slf*JsonLog)WithKey(keystring)Encoder{
slf.val=slf.val+key+""
returnslf
//WithField添加字段.
func(slf*JsonLog)WithField(key,valstring)Encoder{
slf.fields=append(slf.fields,zap.String(key,val))
returnslf
func(slf*JsonLog)Debug(msgstring){
_logger.Debug(slf.val+msg,slf.fields...)
func(slf*JsonLog)Debugf(formatstring,v...interface{}){
_logger.Debug(fmt.Sprintf(slf.val+format,v...),slf.fields...)
func(slf*JsonLog)Info(msgstring){
_logger.Info(slf.val+msg,slf.fields...)
func(slf*JsonLog)Infof(formatstring,v...interface{}){
_logger.Info(fmt.Sprintf(slf.val+format,v...),slf.fields...)
func(slf*JsonLog)Warn(msgstring){
_logger.Warn(slf.val+msg,slf.fields...)
func(slf*JsonLog)Warnf(formatstring,v...interface{}){
_logger.Warn(fmt.Sprintf(slf.val+format,v...),slf.fields...)
func(slf*JsonLog)Error(msgstring){
_logger.Erro
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 天津2025年天津市審計(jì)局所屬事業(yè)單位招聘筆試歷年參考題庫(kù)附帶答案詳解
- 天津2025年天津中醫(yī)藥大學(xué)第一附屬醫(yī)院招聘96人筆試歷年參考題庫(kù)附帶答案詳解
- 2026年陜寧晉青海四省高三語(yǔ)文1月聯(lián)考試卷附答案解析
- 臺(tái)州浙江臺(tái)州市椒江區(qū)市場(chǎng)開(kāi)發(fā)服務(wù)中心招聘筆試歷年參考題庫(kù)附帶答案詳解
- 北京2025年首都醫(yī)科大學(xué)附屬北京朝陽(yáng)醫(yī)院招聘4人筆試歷年參考題庫(kù)附帶答案詳解
- 2025年中醫(yī)藥基礎(chǔ)理論知識(shí)考核答案及解析
- 2025年公務(wù)員招聘考試試題及答案
- 黑龍江護(hù)理單招試題及答案題庫(kù)
- 2025舞蹈聯(lián)考理論試題及答案
- 有關(guān)安全條款的裝修合同
- 心血管疾病風(fēng)險(xiǎn)評(píng)估
- 慢性肝病患者營(yíng)養(yǎng)支持護(hù)理培訓(xùn)
- 2025年云服務(wù)器采購(gòu)合同協(xié)議
- 汽車(chē)租賃業(yè)應(yīng)急預(yù)案(3篇)
- 基層高血壓管理流程
- 2026年咨詢(xún)工程師咨詢(xún)實(shí)務(wù)考前沖刺重點(diǎn)知識(shí)考點(diǎn)總結(jié)記憶筆記
- 2025年內(nèi)蒙古自治區(qū)呼和浩特市評(píng)審專(zhuān)家考試題庫(kù)(一)
- 電化學(xué)儲(chǔ)能電站安全檢查要點(diǎn)表
- 空軍招飛心理測(cè)試題及答案解析
- 2025年及未來(lái)5年中國(guó)凹凸棒石市場(chǎng)競(jìng)爭(zhēng)格局及投資戰(zhàn)略規(guī)劃報(bào)告
- 新解讀《JB-T 3162-2011滾珠絲杠副 絲杠軸端型式尺寸》
評(píng)論
0/150
提交評(píng)論