github.com/divyam234/rclone@v1.64.1/fs/log/caller_hook.go (about) 1 package log 2 3 import ( 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 12 type CallerHook struct { 13 Field string 14 Skip int 15 levels []logrus.Level 16 } 17 18 // NewCallerHook use to make a hook 19 func 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 32 func (h *CallerHook) Levels() []logrus.Level { 33 return logrus.AllLevels 34 } 35 36 // Fire logs the information of context (filename and line) 37 func (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 43 func 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.Contains(file, "log.go") { 49 break 50 } 51 } 52 return fmt.Sprintf("%s:%d", file, line) 53 } 54 55 func 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 }