前言:
logrus是go中比較好的一個log模塊.github上的很多開源項目都在使用這個模塊, 我在寫這個博文時, github上的logrus的stars數已經有8214了.最近在用這個模塊時,發現不能打印日志所在文件和行數.在開發過程中, 感覺這就不是很友好了.
項目地址: logrus github 地址
提醒:此方法在並發情況下, 會導致系統奔潰. 請謹慎使用
不記錄文件名和行號處理辦法
logrus支持自定義的hook, 我這里就是使用hook的方式來記錄
一個Entry為一條日志記錄, 我們的Hook需要做的就是在每一個條的日志記錄里面添加調用時的文件名和行號. 核心就是實現自己的Fire方法, 以下是參考實現:
1. 我們新建一個hook的文件. 寫入如下代碼
package hooks import ( "fmt" "runtime" "strings" "github.com/sirupsen/logrus" ) // ContextHook for log the call context type contextHook struct { Field string Skip int levels []logrus.Level } // NewContextHook use to make an hook // 根據上面的推斷, 我們遞歸深度可以設置到5即可. func NewContextHook(levels ...logrus.Level) logrus.Hook { hook := contextHook{ Field: "line", Skip: 5, levels: levels, } if len(hook.levels) == 0 { hook.levels = logrus.AllLevels } return &hook } // Levels implement levels func (hook contextHook) Levels() []logrus.Level { return logrus.AllLevels } // Fire implement fire func (hook contextHook) Fire(entry *logrus.Entry) error { entry.Data[hook.Field] = findCaller(hook.Skip) return nil } // 對caller進行遞歸查詢, 直到找到非logrus包產生的第一個調用. // 因為filename我獲取到了上層目錄名, 因此所有logrus包的調用的文件名都是 logrus/... // 因此通過排除logrus開頭的文件名, 就可以排除所有logrus包的自己的函數調用 func findCaller(skip int) string { file := "" line := 0 for i := 0; i < 10; i++ { file, line = getCaller(skip + i) if !strings.HasPrefix(file, "logrus") { break } } return fmt.Sprintf("%s:%d", file, line) } // 這里其實可以獲取函數名稱的: fnName := runtime.FuncForPC(pc).Name() // 但是我覺得有 文件名和行號就夠定位問題, 因此忽略了caller返回的第一個值:pc // 在標准庫log里面我們可以選擇記錄文件的全路徑或者文件名, 但是在使用過程成並發最合適的, // 因為文件的全路徑往往很長, 而文件名在多個包中往往有重復, 因此這里選擇多取一層, 取到文件所在的上層目錄那層. func getCaller(skip int) (string, int) { _, file, line, ok := runtime.Caller(skip) //fmt.Println(file) //fmt.Println(line) if !ok { return "", 0 } n := 0 for i := len(file) - 1; i > 0; i-- { if file[i] == '/' { n++ if n >= 2 { file = file[i+1:] break } } } return file, line }
2. 添加hook到logrus -- ( logrus定義為了全局使用 )
package main import ( log "github.com/sirupsen/logrus" zzxHook "study/ginStudy/hook" ) func main() { var Logger = log.New() Logger.Hooks.Add(zzxHook.NewContextHook()) Logger.WithFields(log.Fields{ "animal": "walrus", }).Info("A walrus appears") }
效果:
2. 添加hook到logrus -- ( logrus普通使用方式 )
package main import ( log "github.com/sirupsen/logrus" zzxHook "study/ginStudy/hook" ) func main() { log.AddHook(zzxHook.NewContextHook()) log.WithFields(log.Fields{ "animal": "walrus", }).Info("A walrus appears") }
效果: