日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

go使用zap + lumberjack重构项目的日志系统

發(fā)布時(shí)間:2023/12/8 windows 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 go使用zap + lumberjack重构项目的日志系统 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

【工作隨筆】重構(gòu)項(xiàng)目的日志系統(tǒng)

原先公司的go項(xiàng)目是采用之前一個(gè)大哥自己開發(fā)的一個(gè)log包,來實(shí)現(xiàn)各種日志的打印監(jiān)控,對(duì)于和很多的場景支持和日志分割都做的不太好,所以在近期有空的時(shí)候?qū)系娜罩鞠到y(tǒng)進(jìn)行了重寫。

1 明確優(yōu)化需求

  • 性能強(qiáng)勁(至少要比老的好)
  • 兼容老的日志代碼,減少改動(dòng)(不然就得改成百上千行代碼)
  • 支持日志按天分割(別的C++的服務(wù)都是這么分割,要方便運(yùn)維開發(fā)監(jiān)控腳本)

2 前期準(zhǔn)備

在網(wǎng)絡(luò)上看了很多的大牛寫的介紹決定采用【zap + lumberjack】兩個(gè)包來實(shí)現(xiàn)我們的新日志系統(tǒng),這也是現(xiàn)在go語言常見的一種日志解決方案

  • Zap go.uber.org/zap
    現(xiàn)在最強(qiáng)大的go logger包之一,官方文檔附在超連接里,性能強(qiáng)大調(diào)用精簡。并且zap提供了兩種類型的 logger
SugaredLoggerLogger 省流介紹:Logger只支持強(qiáng)類型,當(dāng)是性能更強(qiáng),我們的項(xiàng)目為了兼容老代碼所以選擇SugaredLogger
  • lumberjack github.com/natefinch/lumberjack

是一個(gè)支持日志分割,日志過期刪除的小包,非常適配Zap

3 擼代碼

首先是創(chuàng)建一個(gè)可以打印日志的SugaredLogger

package loggerimport ("github.com/natefinch/lumberjack""go.uber.org/zap""go.uber.org/zap/zapcore" )var Svrlogger Logger// 為了兼容老代碼,選擇自己封裝一層 type Logger struct {logger *zap.SugaredLogger }// 創(chuàng)建一個(gè)lumberjack的Write func getLogWriter() zapcore.WriteSyncer {lumberJackLogger := &lumberjack.Logger{Filename: "./logPath",MaxSize: 10, // 日志大小(塞滿了才創(chuàng)建新的)// 備份相關(guān)的參數(shù)MaxBackups: 10,MaxAge: 10,Compress: false,}return zapcore.AddSync(lumberJackLogger) }func InitLogger() {// 設(shè)置一些基本日志格式encoder := zapcore.NewConsoleEncoder(zapcore.EncoderConfig{// 略~})// 創(chuàng)建一個(gè)corecore := zapcore.NewCore(encoder, getLogWriter(), zapcore.DebugLevel)// 給logger賦值logger := zap.New(core, zap.AddCaller())sugarLogger = logger.Sugar() }

Demo寫完了,測試了一下沒有問題,接下里我們思考下一個(gè)問題:
我們期望的是日志隨日期的變化來打印,即換天之后創(chuàng)建新的日志,然后往新的日志中打印,而lumberjack的日志打印模式是先給日志文件設(shè)置最大的大小,如果日志內(nèi)容超過這個(gè)大小才會(huì)創(chuàng)建新的日志文件,這顯然是不符合我們要求的,所以沒辦法手撕lumberjack,還好就百來行代碼重寫一下就行了。

// 關(guān)鍵的函數(shù)改Write就行了,別的函數(shù)的改動(dòng)我就不細(xì)寫了 func (l *LoggerWriter) Write(p []byte) (n int, err error) {l.mu.Lock()defer l.mu.Unlock()/* 代碼略...*/t := currentTime()// 判斷是不是換天了,如果換天了就要重新調(diào)用rotate()if l.update.Day() != t.Day() || l.update.Month() != t.Month() || l.update.Year() != t.Year() {if err := l.rotate(); err != nil {return 0, err}}/* 代碼略...*/n, err = l.file.Write(p)return n, err }

解決了lumberjack的問題之后,我又發(fā)現(xiàn)了新的問題:
首先我們期望debug,info 這類信息的日志信息更適合用于保活信息的打印,這類信息應(yīng)該交由運(yùn)維同學(xué)監(jiān)控,而我們開發(fā)成員更應(yīng)該關(guān)注Warn,Error,Fatal,Painc;所以更好的實(shí)現(xiàn)方式應(yīng)該是一個(gè)go服務(wù)同時(shí)打印兩份文件,所以我們一個(gè)logger實(shí)例就需要?jiǎng)?chuàng)建多個(gè)zapcore!

func InitLogger() {/*不重要的代碼...*/savelog := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {return lvl <= zapcore.InfoLevel})errorlog := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {return lvl >= zapcore.WarnLevel})// 使用了core的NewTeecore := zapcore.NewTee(// 保活日志zapcore.NewCore(encoder, zapcore.AddSync(getLogWriter("./save/log")), savelog ),// 錯(cuò)誤日志zapcore.NewCore(encoder, zapcore.AddSync(getLogWriter("./error/log")), errorlog ),)/*不重要的代碼...*/log := zap.New(core, zap.AddCaller())Svrlogger.logger := log.Sugar() }

打印兩個(gè)日志的問題解決之后,我又了個(gè)新的鬼點(diǎn)子,我希望打印的錯(cuò)誤日志也可以在程序終端進(jìn)行輸出!所以還得要改改!使用io包的io.MultiWriter方法,讓zap的日志往終端和文件都能打印

func InitLogger() {/*不重要的代碼...*/core := zapcore.NewTee(// 保活日志zapcore.NewCore(encoder, zapcore.AddSync(getLogWriter("./save/log")), savelog ),// 錯(cuò)誤日志zapcore.NewCore(encoder, zapcore.AddSync(io.MultiWriter(os.Stdout,getLogWriter("./error/log"))), errorlog ),)/*不重要的代碼...*/ }

最后新的日志系統(tǒng)提交測試之后,發(fā)現(xiàn)我開發(fā)的時(shí)候忘記了自己是在zap的外面包了一層,所以打印日志堆棧信息的時(shí)候,打印的調(diào)用函數(shù)都是logger.go,我就回到go.uber.org/zap的文檔里一陣翻閱找到了這個(gè)方法:

// AddCallerSkip increases the number of callers skipped by caller annotation // (as enabled by the AddCaller option). When building wrappers around the // Logger and SugaredLogger, supplying this Option prevents zap from always // reporting the wrapper code as the caller. func AddCallerSkip(skip int) Option {return optionFunc(func(log *Logger) {log.callerSkip += skip}) }

他允許我們打印調(diào)用堆棧信息的時(shí)候向上skip,所以我們最后的代碼變成了這樣子

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

以上,代碼都是精簡省流版本,更加環(huán)保,更加便于閱讀,希望對(duì)大家有所幫助

總結(jié)

以上是生活随笔為你收集整理的go使用zap + lumberjack重构项目的日志系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。