Golang logrus 日誌包及日誌切割的實現
本文主要介紹 Golang 中最佳日誌解決方案,包括常用日誌包logrus 的基本使用,如何結合file-rotatelogs 包實現日誌檔案的輪轉切割兩大話題。
Golang 關於日誌處理有很多包可以使用,標準庫提供的 log 包功能比較少,不支援日誌級別的精確控制,自定義新增日誌欄位等。在眾多的日誌包中,更推薦使用第三方的 logrus 包,完全相容自帶的 log 包。logrus 是目前 Github 上 star 數量最多的日誌庫,logrus 功能強大,效能高效,而且具有高度靈活性,提供了自定義外掛的功能。
很多開源專案,如 docker,prometheus,dejavuzhou/ginbro 等,都是用了 logrus 來記錄其日誌。
logrus 特性
- 完全相容 golang 標準庫日誌模組:logrus 擁有六種日誌級別:debug、info、warn、error、fatal 和 panic,這是 golang 標準庫日誌模組的 API 的超集。
- logrus.Debug(“Useful debugging information.”)
- logrus.Info(“Something noteworthy happened!”)
- logrus.Warn(“You should probably take a look at this.”)
- logrus.Error(“Something failed but I'm not quitting.”)
- logrus.Fatal(“Bye.”) //log之後會呼叫os.Exit(1)
- logrus.Panic(“I'm bailing.”) //log之後會panic()
- 可擴充套件的 Hook 機制:允許使用者通過 hook 的方式將日誌分發到任意地方,如本地檔案系統、標準輸出、logstash、elasticsearch 或者 mq 等,或者通過 hook 定義日誌內容和格式等。
- 可選的日誌輸出格式:logrus 內建了兩種日誌格式,JSONFormatter 和 TextFormatter,如果這兩個格式不滿足需求,可以自己動手實現介面 Formatter 介面來定義自己的日誌格式。
- Field 機制:logrus 鼓勵通過 Field 機制進行精細化的、結構化的日誌記錄,而不是通過冗長的訊息來記錄日誌。
- logrus 是一個可插拔的、結構化的日誌框架。
- Entry: logrus.WithFields 會自動返回一個 *Entry,Entry裡面的有些變數會被自動加上
- time:entry被建立時的時間戳
- msg:在呼叫.Info()等方法時被新增
- level,當前日誌級別
logrus 基本使用
package main import ( "os" "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus" ) var logger *logrus.Entry func init() { // 設定日誌格式為json格式 log.SetFormatter(&log.JSONFormatter{}) log.SetOutput(os.Stdout) log.SetLevel(log.InfoLevel) logger = log.WithFields(log.Fields{"request_id": "123444","user_ip": "127.0.0.1"}) } func main() { logger.Info("hello,logrus....") logger.Info("hello,logrus1....") // log.WithFields(log.Fields{ // "animal": "walrus",// "size": 10,// }).Info("A group of walrus emerges from the ocean") // log.WithFields(log.Fields{ // "omg": true,// "number": 122,// }).Warn("The group's number increased tremendously!") // log.WithFields(log.Fields{ // "omg": true,// "number": 100,// }).Fatal("The ice breaks!") }
基於 logrus 和 file-rotatelogs 包實現日誌切割
很多時候應用會將日誌輸出到檔案系統,對於訪問量大的應用來說日誌的自動輪轉切割管理是個很重要的問題,如果應用不能妥善處理日誌管理,那麼會帶來很多不必要的維護開銷:外部工具切割日誌、人工清理日誌等手段確保不會將磁碟打滿。
file-rotatelogs: When you integrate this to to you app,it automatically write to logs that are rotated from within the app: No more disk-full alerts because you forgot to setup logrotate!
logrus 本身不支援日誌輪轉切割功能,需要配合 file-rotatelogs 包來實現,防止日誌打滿磁碟。file-rotatelogs 實現了 io.Writer 介面,並且提供了檔案的切割功能,其例項可以作為 logrus 的目標輸出,兩者能無縫整合,這也是 file-rotatelogs 的設計初衷:
It's normally expected that this library is used with some other logging service,such as the built-in log library,or loggers such as github.com/lestrrat-go/apache-logformat.
示例程式碼:
應用日誌檔案 /Users/opensource/test/go.log,每隔 1 分鐘輪轉一個新檔案,保留最近 3 分鐘的日誌檔案,多餘的自動清理掉。
package main import ( "time" rotatelogs "github.com/lestrrat-go/file-rotatelogs" log "github.com/sirupsen/logrus" ) func init() { path := "/Users/opensource/test/go.log" /* 日誌輪轉相關函式 `WithLinkName` 為最新的日誌建立軟連線 `WithRotationTime` 設定日誌分割的時間,隔多久分割一次 WithMaxAge 和 WithRotationCount二者只能設定一個 `WithMaxAge` 設定檔案清理前的最長儲存時間 `WithRotationCount` 設定檔案清理前最多儲存的個數 */ // 下面配置日誌每隔 1 分鐘輪轉一個新檔案,保留最近 3 分鐘的日誌檔案,多餘的自動清理掉。 writer,_ := rotatelogs.New( path+".%Y%m%d%H%M",rotatelogs.WithLinkName(path),rotatelogs.WithMaxAge(time.Duration(180)*time.Second),rotatelogs.WithRotationTime(time.Duration(60)*time.Second),) log.SetOutput(writer) //log.SetFormatter(&log.JSONFormatter{}) } func main() { for { log.Info("hello,world!") time.Sleep(time.Duration(2) * time.Second) } }
Golang 標準日誌庫 log 使用
雖然 Golang 標準日誌庫功能少,但是可以選擇性的瞭解下,下面為基本使用的程式碼示例,比較簡單:
package main import ( "fmt" "log" ) func init() { log.SetPrefix("【UserCenter】") // 設定每行日誌的字首 log.SetFlags(log.LstdFlags | log.Lshortfile | log.LUTC) // 設定日誌的抬頭欄位 } func main() { log.Println("log...") log.Fatalln("Fatal Error...") fmt.Println("Not print!") }
自定義日誌輸出
package main import ( "io" "log" "os" ) var ( Info *log.Logger Warning *log.Logger Error *log.Logger ) func init() { errFile,err := os.OpenFile("errors.log",os.O_CREATE|os.O_WRONLY|os.O_APPEND,0666) if err != nil { log.Fatalln("開啟日誌檔案失敗:",err) } Info = log.New(os.Stdout,"Info:",log.Ldate|log.Ltime|log.Lshortfile) Warning = log.New(os.Stdout,"Warning:",log.Ldate|log.Ltime|log.Lshortfile) Error = log.New(io.MultiWriter(os.Stderr,errFile),"Error:",log.Ldate|log.Ltime|log.Lshortfile) } func main() { Info.Println("Info log...") Warning.Printf("Warning log...") Error.Println("Error log...") }
相關文件
https://mojotv.cn/2018/12/27/golang-logrus-tutorial
https://github.com/lestrrat-go/file-rotatelogs
https://www.flysnow.org/2017/05/06/go-in-action-go-log.html
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。