1package log 2 3import ( 4 "fmt" 5 "runtime" 6 "strings" 7 8 "github.com/sirupsen/logrus" 9) 10 11// CallerHook for log the calling file and line of the fine 12type CallerHook struct { 13 Field string 14 Skip int 15 levels []logrus.Level 16} 17 18// NewCallerHook use to make a hook 19func NewCallerHook(levels ...logrus.Level) logrus.Hook { 20 hook := CallerHook{ 21 Field: "source", 22 Skip: 7, 23 levels: levels, 24 } 25 if len(hook.levels) == 0 { 26 hook.levels = logrus.AllLevels 27 } 28 return &hook 29} 30 31// Levels implement applied hook to which levels 32func (h *CallerHook) Levels() []logrus.Level { 33 return logrus.AllLevels 34} 35 36// Fire logs the information of context (filename and line) 37func (h *CallerHook) Fire(entry *logrus.Entry) error { 38 entry.Data[h.Field] = findCaller(h.Skip) 39 return nil 40} 41 42// findCaller ignores the caller relevant to logrus or fslog then find out the exact caller 43func findCaller(skip int) string { 44 file := "" 45 line := 0 46 for i := 0; i < 10; i++ { 47 file, line = getCaller(skip + i) 48 if !strings.HasPrefix(file, "logrus") && strings.Index(file, "log.go") < 0 { 49 break 50 } 51 } 52 return fmt.Sprintf("%s:%d", file, line) 53} 54 55func getCaller(skip int) (string, int) { 56 _, file, line, ok := runtime.Caller(skip) 57 // fmt.Println(file,":",line) 58 if !ok { 59 return "", 0 60 } 61 n := 0 62 for i := len(file) - 1; i > 0; i-- { 63 if file[i] == '/' { 64 n++ 65 if n >= 2 { 66 file = file[i+1:] 67 break 68 } 69 } 70 } 71 return file, line 72} 73