Go項目實戰之日志必備篇[開源十年項目第11次更新]

Golang中文社區 2022-05-14 12:58:26 阅读数:309

之日日志十年更新
一個深漂近10年的程序員立志用未來10年時間去維護一個項目,這個項目的功能未定,用到什麼就做什麼,遇到什麼就寫什麼。其主要目的有二,一為加深自己的技術深度,二為其他學習者提供參考。感興趣的可以跟著我一起做這個項目,不收費、不套路、人間自有真情在。備注:前面項目中用到的代碼已經分享到GitHub中去了,並且以後所有項目中會出現的代碼都會提交上去,歡迎查閱。地址:https://github.com/kaiyuan10nian/kaiyuan10nian 感興趣的可以點個star哦~開源十年項目的更新首發於公眾號:計算機自學平臺,有興趣的小夥伴可以持續關注,並歡迎各比特加我的微信(kaiyuan10nian)跟我一起完成並推動項目的發展。---哎呀呀,這次更新間隔拉得有點久,是在是對不住各比特支持我的小夥伴,最近公司剛啟動了一個新項目,時間實在是緊張,希望各比特多多見諒。下面開始今天的分享正文。**Go項目實戰之日志必備篇**你在某公司技術部經常聽到的一句話就是:“稍等,讓我查下**日志**再回複你。”日志---其實就是項目在運行期間留下的痕迹。就好比你冬天去打兔子,第一件事就是找雪地上兔子留下的脚印,然後順著脚印去找到兔子的老窩,最後滿載而歸。項目開發也是一樣的道理,你要在項目開發期間想盡辦法去讓業務邏輯在運行期間能留下更多的關鍵信息,這樣在項目正常運行後就會留下它運行的痕迹,你就可以通過這個痕迹快速尋找到問題的根源,從而一網打盡。而在Go語言中只提供了一個標准庫log.不需要安裝即可使用,它是一個非常小巧的日志庫,大家有空可以去看看。log只提供了三個簡單的接口,對於某些大型項目來說有點太雞肋,所以本篇我要介紹的不是log而是它的哥哥logrus。logrus是一個完全兼容log的標准庫,目前在GitHub上已經超20K stars了。它支持兩種日志輸出格式:文本 And JSON這對於想通過日志去做更多數據分析的項目來說簡直是太爽了。本篇分兩部分:- 1、logrus的基本用法介紹- 2、封裝logrus用於**開源十年**項目中​ 2.1)關於使用lumberjack對logrus生成的日志進行分包1、logrus的基本用法介紹1)安裝```gogo get -u github.com/sirupsen/logrus```2)設置日志輸出等級​ 老程序員都知道,一個項目完整的開發周期分好幾個階段,所以在不同的階段我們需要的日志信息也是不一樣的。所以在使用logrus的時候我們要去設置其日志輸出的等級,從而篩選出我們需要的信息內容。​ 那麼在設置日志輸出等級之前,我們需要了解logrus共區分了幾個等級?| 級別 | 等級 | 解釋 || ---- | ----------------- | ---------------------------------------------------- || 1 | logrus.TraceLevel | 非常小粒度的信息 || 2 | logrus.DebusLevel | 一般程序中輸出的調試信息 || 3 | logrus.InfoLevel | 關鍵操作(核心流程日志) || 4 | logrus.WarnLevel | 警告信息 || 5 | logrus.ErrorLevel | 錯誤信息 || 6 | logrus.FatalLevel | 致命錯誤,出現後程序無法運行,輸出日之後程序停止運行 || 7 | logrus.PanicLevel | 記錄日志,然後panic |左邊有個**級別** 大家一定要記清楚順序,因為在logrus中,高於設置級別的日志是不會輸出的,默認設置級別是InfoLevel示例:```gologrus.SetLevel(logrus.TraceLevel)logrus.Trace("1---trace---msg")logrus.Debug("2---debug---msg")logrus.Info("3---info---msg")logrus.Warn("4---warn---msg")logrus.Error("5---error---msg")logrus.Fatal("6---fatal---msg")logrus.Panic("7---panic---msg")```運行之後我們看下日志輸出情况:```goTRAC[0000] 1---trace---msg DEBU[0000] 2---debug---msg INFO[0000] 3---info---msg WARN[0000] 4---warn---msg ERRO[0000] 5---error---msg FATA[0000] 6---fatal---msg ```如果上面代碼中我們把:```gologrus.SetLevel(logrus.TraceLevel)```修改為:```gologrus.SetLevel(logrus.InfoLevel)```然後,再運行看下輸出情况:```goINFO[0000] 3---info---msg WARN[0000] 4---warn---msg ERRO[0000] 5---error---msg FATA[0000] 6---fatal---msg ```可以看到,比info級別低的就不再輸出了。3)在日志中輸出具體文件和函數比特置為了快速定比特問題根源,很多時候我們會在調試階段直接把文件路徑和函數直接輸出出來,這樣我們就不需要再去定比特尋找了,解决問題的效率將會得到大大的提昇。logrus提供了專門的配置,只需要在初始化logrus的時候調用SetReportCaller()函數並設置為true即可。示例:```go logrus.SetReportCaller(true) logrus.Info("3---info---msg")```直接運行看效果:```goINFO[0000]/Users/fu/GolandProjects/logrusDemo/main.go:29 main.main() 3---info---msg ```4)添加附屬信息我們做為後端開發人員,時刻把並發的問題放在心頭是本能。所以在記錄日志時,你可能也會思考怎麼去區分日志。比如:哪些日志是張三留下的?哪些日志是李四留下的?為什麼同樣的邏輯流程張三和李四輸出的結果不一樣呢?這個時候你或許在想,如果我給這些日志打上“張三”“李四”的備注是不是就好找多了?logrus提供了解决方案,就是WithField和WithFields ,允許在輸出中添加一些字段,比如:```gologrus.WithFields(logrus.Fields{ "UUID": "12345678", }).Info("info msg")```日志輸出:```goINFO[0000] 3---info---msg UUID=12345678```這是針對單個的使用方式,如果想批量使用更好辦:```gorequestLogger := logrus.WithFields(logrus.Fields{ "UUID": "12345678", })requestLogger.Info("3---info---msg")requestLogger.Error("5---error---msg")```日志輸出:```goINFO[0000] 3---info---msg UUID=12345678ERRO[0000] 5---error---msg UUID=12345678```5)JSON格式輸出日志上面我們輸出日志的時候用的是默認的輸出格式,也就是文本格式。但是在很多業務中我們做數據統計或者數據分析的時候依靠的源數據都是日志,如果是文本格式那麼用起來就不是那麼的順手,換成json格式的話會不會帶來很大的方便呢?logrus不同於log的最大之處就是提供了json格式的輸出,只需要在初始化的時候設置SetFormatter即可。```go logrus.SetLevel(logrus.TraceLevel) logrus.SetFormatter(&logrus.JSONFormatter{}) logrus.Trace("1---trace---msg") logrus.Debug("2---debug---msg") logrus.Info("3---info---msg") logrus.Warn("4---warn---msg") logrus.Error("5---error---msg") logrus.Fatal("6---fatal---msg") logrus.Panic("7---panic---msg")```跟1)中的實例一樣,只是添加了logrus.SetFormatter(&logrus.JSONFormatter{}),下面我們看下輸出的格式:```go{"level":"trace","msg":"1---trace---msg","time":"2022-05-14T11:37:56+08:00"}{"level":"debug","msg":"2---debug---msg","time":"2022-05-14T11:37:56+08:00"}{"level":"info","msg":"3---info---msg","time":"2022-05-14T11:37:56+08:00"}{"level":"warning","msg":"4---warn---msg","time":"2022-05-14T11:37:56+08:00"}{"level":"error","msg":"5---error---msg","time":"2022-05-14T11:37:56+08:00"}{"level":"fatal","msg":"6---fatal---msg","time":"2022-05-14T11:37:56+08:00"}```ok,到這裏logrus的基本操作我們就明白了,下面針對在開源十年項目中我們怎麼去系統的運用它。2、封裝logrus用於**開源十年**項目中我封裝了一個logger.go的文件,放在了config目錄下面,下面我把代碼完整放上來,然後在備注中去一一解釋一下。```gopackage configimport ( "github.com/gin-gonic/gin" "github.com/natefinch/lumberjack" "github.com/sirupsen/logrus" "path" "time")var logger *logrus.Logger//日志名稱const ( //日志文件名 LOG_NAME = "kaiyuanshinian" //日志文件後綴 LOG_SUFFIX = ".log" //單個日志文件大小,單比特MB LOG_SIZE = 50 //日志文件個數 LOG_BACKUP = 10 //日志文件最大天數 LOG_DATE = 7)//設置日志輸出到文件func setOutPut(log *logrus.Logger, log_file_path string) { logconf := &lumberjack.Logger{ Filename: log_file_path, MaxSize: LOG_SIZE, // 日志文件大小,單比特是 MB MaxBackups: LOG_BACKUP, // 最大過期日志保留個數 MaxAge: LOG_DATE, // 保留過期文件最大時間,單比特 天 Compress: true, // 是否壓縮日志,默認是不壓縮。這裏設置為true,壓縮日志 } log.SetOutput(logconf)}//初始化日志模塊func InitLogger() { log_file_path := path.Join("./", LOG_NAME+LOG_SUFFIX) logger = logrus.New() setOutPut(logger, log_file_path) logger.SetLevel(logrus.DebugLevel) logger.SetFormatter(&logrus.JSONFormatter{ TimestampFormat: "2006-01-02 15:04:05", })}//獲取logrus操作對象func GetLogger() *logrus.Logger { return logger}//gin請求消息也寫入日志func LoggerToFile() gin.HandlerFunc { return func(c *gin.Context) { startTime := time.Now() // 開始時間 c.Next() // 處理請求 endTime := time.Now() // 結束時間 latencyTime := endTime.Sub(startTime) // 執行時間 reqMethod := c.Request.Method // 請求方式 reqUri := c.Request.RequestURI // 請求路由 statusCode := c.Writer.Status() // 狀態碼 clientIP := c.ClientIP() // 請求IP logger.Infof("| %3d | %13v | %15s | %s | %s", statusCode, latencyTime, clientIP, reqMethod, reqUri ) // 日志格式 }}```上面是對logrus的封裝,大家應該都看的明白的我就不一一囉嗦了,那麼怎麼使用呢?(上面代碼中只有lumberjack是我們之前沒有提及過得,下面解釋)1)初始化直接在項目啟動的時候把logrus的初始化加進去即可```gofunc InitConfig() { config.InitLogger()//初始化logrus viper.SetConfigName("application") viper.SetConfigType("yml") viper.AddConfigPath("./config/") err := viper.ReadInConfig() if err != nil { panic(""+err.Error()) }}```2)使用使用就更簡單了,直接在項目需要的比特置進行調用即可。2.1)route中的使用```gofunc CollectRoute(r *gin.Engine) *gin.Engine { r.Use(config.LoggerToFile())//添加日志記錄 r.POST("/v1/account/register", controller.Register) ...//省略了一些代碼,都是以前寫的,項目中有 return r}```2.2)邏輯中的使用```goconfig.GetLogger().Debugf("aaaaa")```3)lumberjack上面封裝的代碼中大家發現多了個新東西lumberjack,他是幹啥用的呢?對,切分日志文件的。有的時候我們的日志需要大量的去記載,如果都記錄在一個文件中,萬一發生點什麼不可描述的事情導致文件丟失了那我們就只有哭的份了。所以一是為了安全,二是為了方便,我們要針對日志文件進行分割保存。```gologconf := &lumberjack.Logger{ Filename: log_file_path, MaxSize: LOG_SIZE, // 日志文件大小,單比特是 MB MaxBackups: LOG_BACKUP, // 最大過期日志保留個數 MaxAge: LOG_DATE, // 保留過期文件最大時間,單比特 天 Compress: true, // 是否壓縮日志,默認是不壓縮。這裏設置為true,壓縮日志 } log.SetOutput(logconf)```它的使用非常簡單,設置好參數,在SetoutPut中傳入進去就可以了,當文件大於我們設定的MaxSize時,會自動進行分割保存。ok ,just this...今天就先寫這麼多吧。謝謝大家的支持哦~
版权声明:本文为[Golang中文社區]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/134/202205141252132918.html