@@ -60,11 +60,28 @@ type Logger logrus.Logger
6060type Fields logrus.Fields
6161
6262// CallerHook defines caller awareness hook for logrus.
63- type CallerHook struct {}
63+ type CallerHook struct {
64+ StackLevels []logrus.Level
65+ }
66+
67+ // NewCallerHook creates new CallerHook
68+ func NewCallerHook (stackLevels []logrus.Level ) * CallerHook {
69+ return & CallerHook {
70+ StackLevels : stackLevels ,
71+ }
72+ }
73+
74+ // StandardCallerHook is a convenience initializer for LogrusStackHook{} with
75+ // default args.
76+ func StandardCallerHook () * CallerHook {
77+ return NewCallerHook (
78+ []logrus.Level {logrus .PanicLevel , logrus .FatalLevel , logrus .ErrorLevel },
79+ )
80+ }
6481
6582// Fire defines hook event handler.
6683func (hook * CallerHook ) Fire (entry * logrus.Entry ) error {
67- funcDesc , caller := hook .caller ()
84+ funcDesc , caller := hook .caller (entry )
6885 fields := strings .SplitN (funcDesc , "." , 2 )
6986 if len (fields ) > 0 {
7087 level , ok := PkgDebugLogFilter [fields [0 ]]
@@ -91,38 +108,61 @@ func (hook *CallerHook) Levels() []logrus.Level {
91108 }
92109}
93110
94- func (hook * CallerHook ) caller () (relFuncName , caller string ) {
95- var (
96- file = "unknown"
97- line = 0
98- funcName = "unknown"
99- )
111+ func (hook * CallerHook ) caller (entry * logrus.Entry ) (relFuncName , caller string ) {
112+ var skipFrames int
113+ if len (entry .Data ) == 0 {
114+ // When WithField(s) is not used, we have 8 logrus frames to skip.
115+ skipFrames = 8
116+ } else {
117+ // When WithField(s) is used, we have 6 logrus frames to skip.
118+ skipFrames = 6
119+ }
120+
100121 pcs := make ([]uintptr , 12 )
101- if runtime .Callers (6 , pcs ) > 0 {
102- frames := runtime .CallersFrames (pcs )
122+ stacks := make ([]runtime.Frame , 0 , 12 )
123+ if runtime .Callers (skipFrames , pcs ) > 0 {
124+ var foundCaller bool
125+ _frames := runtime .CallersFrames (pcs )
103126 for {
104- f , more := frames .Next ()
127+ f , more := _frames .Next ()
105128 //fmt.Printf("%s:%d %s\n", f.File, f.Line, f.Function)
106- if strings .HasSuffix (f .File , "logwrapper.go" ) && more {
107- f , _ = frames .Next ()
108- file = f .File
109- line = f .Line
110- funcName = f .Function
111- break
129+ if ! foundCaller && strings .HasSuffix (f .File , "logwrapper.go" ) && more {
130+ f , _ = _frames .Next ()
131+ relFuncName = strings .TrimPrefix (f .Function , "github.com/CovenantSQL/CovenantSQL/" )
132+ caller = fmt .Sprintf ("%s:%d %s" , filepath .Base (f .File ), f .Line , relFuncName )
133+ foundCaller = true
134+ }
135+ if foundCaller {
136+ stacks = append (stacks , f )
112137 }
113138 if ! more {
114139 break
115140 }
116141 }
117142 }
118143
119- relFuncName = strings .TrimPrefix (funcName , "github.com/CovenantSQL/CovenantSQL/" )
120- funcLocation := fmt .Sprintf ("%s:%d %s" , filepath .Base (file ), line , relFuncName )
121- return relFuncName , funcLocation
144+ if len (stacks ) > 0 {
145+ for _ , level := range hook .StackLevels {
146+ if entry .Level == level {
147+ stacksStr := make ([]string , 0 , len (stacks ))
148+ for i , s := range stacks {
149+ if s .Line > 0 {
150+ fName := strings .TrimPrefix (s .Function , "github.com/CovenantSQL/CovenantSQL/" )
151+ stackStr := fmt .Sprintf ("#%d %s@%s:%d " , i , fName , filepath .Base (s .File ), s .Line )
152+ stacksStr = append (stacksStr , stackStr )
153+ }
154+ }
155+ entry .Data ["stack" ] = stacksStr
156+ break
157+ }
158+ }
159+ }
160+
161+ return relFuncName , caller
122162}
123163
124164func init () {
125- AddHook (& CallerHook {} )
165+ AddHook (StandardCallerHook () )
126166}
127167
128168//var (
0 commit comments