GO語(yǔ)言框架快速集成日志模塊的操作方法_第1頁(yè)
GO語(yǔ)言框架快速集成日志模塊的操作方法_第2頁(yè)
GO語(yǔ)言框架快速集成日志模塊的操作方法_第3頁(yè)
GO語(yǔ)言框架快速集成日志模塊的操作方法_第4頁(yè)
GO語(yǔ)言框架快速集成日志模塊的操作方法_第5頁(yè)
已閱讀5頁(yè),還剩10頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論