forked from Gurpartap/logrus-stack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
logrus-stack-hook.go
90 lines (76 loc) · 2.49 KB
/
logrus-stack-hook.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package logrus_stack
import (
"strings"
"github.com/Sirupsen/logrus"
"github.com/facebookgo/stack"
)
// NewHook is the initializer for LogrusStackHook{} (implementing logrus.Hook).
// Set levels to callerLevels for which "caller" value may be set, providing a
// single frame of stack. Set levels to stackLevels for which "stack" value may
// be set, providing the full stack (minus logrus).
func NewHook(callerLevels []logrus.Level, stackLevels []logrus.Level) LogrusStackHook {
return LogrusStackHook{
CallerLevels: callerLevels,
StackLevels: stackLevels,
}
}
// StandardHook is a convenience initializer for LogrusStackHook{} with
// default args.
func StandardHook() LogrusStackHook {
return LogrusStackHook{
CallerLevels: logrus.AllLevels,
StackLevels: []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel},
}
}
// LogrusStackHook is an implementation of logrus.Hook interface.
type LogrusStackHook struct {
// Set levels to CallerLevels for which "caller" value may be set,
// providing a single frame of stack.
CallerLevels []logrus.Level
// Set levels to StackLevels for which "stack" value may be set,
// providing the full stack (minus logrus).
StackLevels []logrus.Level
}
// Levels provides the levels to filter.
func (hook LogrusStackHook) Levels() []logrus.Level {
return logrus.AllLevels
}
// Fire is called by logrus when something is logged.
func (hook LogrusStackHook) Fire(entry *logrus.Entry) error {
var skipFrames int
if len(entry.Data) == 0 {
// When WithField(s) is not used, we have 8 logrus frames to skip.
skipFrames = 7
} else {
// When WithField(s) is used, we have 6 logrus frames to skip.
skipFrames = 5
}
var frames stack.Stack
// Get the complete stack track past skipFrames count.
_frames := stack.Callers(skipFrames)
// Remove logrus's own frames that seem to appear after the code is through
// certain hoops. e.g. http handler in a separate package.
// This is a workaround.
for _, frame := range _frames {
if !strings.Contains(frame.File, "github.com/Sirupsen/logrus") {
frames = append(frames, frame)
}
}
if len(frames) > 0 {
// If we have a frame, we set it to "caller" field for assigned levels.
for _, level := range hook.CallerLevels {
if entry.Level == level {
entry.Data["_@caller"] = frames[0]
break
}
}
// Set the available frames to "stack" field.
for _, level := range hook.StackLevels {
if entry.Level == level {
entry.Data["_@stack"] = frames
break
}
}
}
return nil
}