-
Notifications
You must be signed in to change notification settings - Fork 0
/
log.go
145 lines (129 loc) · 3.32 KB
/
log.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package logrus
import (
"context"
"runtime"
"sync"
"time"
"github.com/sirupsen/logrus"
"github.com/go-kita/log"
)
type callDepthKey struct {
}
type formatter struct {
op *outPutter
formatter logrus.Formatter
}
func (f *formatter) Format(entry *logrus.Entry) ([]byte, error) {
if !entry.HasCaller() {
return f.formatter.Format(entry)
}
callDepth, ok := entry.Context.Value(callDepthKey{}).(int)
if !ok {
return f.formatter.Format(entry)
}
entry.Caller = f.op.callerFunc(callDepth + 8)
return f.formatter.Format(entry)
}
type OutPutterOption func(o *outPutter)
func NowFuncOption(fn func() time.Time) OutPutterOption {
return func(o *outPutter) {
o.nowFunc = fn
}
}
func LevelFuncOption(fn func(level log.Level) logrus.Level) OutPutterOption {
return func(o *outPutter) {
o.levelFunc = fn
}
}
// outPutter is a log.OutPutter based on Zap logger.
type outPutter struct {
out *logrus.Logger
entryPool *sync.Pool
nowFunc func() time.Time
levelFunc func(level log.Level) logrus.Level
callerFunc func(callDepth int) *runtime.Frame
}
// NewOutPutter produce a log.OutPutter based on logrus.Logger
func NewOutPutter(out *logrus.Logger, opts ...OutPutterOption) log.OutPutter {
out = &logrus.Logger{
Out: out.Out,
Hooks: out.Hooks,
Formatter: out.Formatter,
ReportCaller: out.ReportCaller,
Level: out.Level,
ExitFunc: out.ExitFunc,
}
op := &outPutter{
out: out,
entryPool: &sync.Pool{
New: func() interface{} {
return &logrus.Entry{}
},
},
nowFunc: time.Now,
levelFunc: defaultLevelFunc,
callerFunc: defaultCallerFunc,
}
for _, opt := range opts {
opt(op)
}
out.Formatter = &formatter{op, out.Formatter}
return op
}
func (o *outPutter) OutPut(
ctx context.Context, name string, level log.Level, msg string, fields []log.Field, callDepth int) {
ctx = context.WithValue(ctx, callDepthKey{}, callDepth)
entry := o.entryPool.Get().(*logrus.Entry)
defer func() {
entry.Data = map[string]interface{}{}
o.entryPool.Put(entry)
}()
entry.Logger = o.out
entry.Data = make(map[string]interface{}, len(fields)+1)
entry.Data[log.LoggerKey] = name
for _, field := range fields {
if len(field.Key) == 0 {
continue
}
if field.Key == log.LevelKey {
continue
}
entry.Data[field.Key] = log.Value(ctx, field.Value)
}
entry.Time = o.nowFunc()
entry.Context = ctx
entry.Log(o.levelFunc(level), msg)
}
func defaultLevelFunc(level log.Level) logrus.Level {
switch {
case level == log.InfoLevel:
return logrus.InfoLevel
case level == log.WarnLevel:
return logrus.WarnLevel
case level == log.ErrorLevel:
return logrus.ErrorLevel
case level == log.DebugLevel:
return logrus.DebugLevel
case level < log.DebugLevel:
return logrus.TraceLevel
default:
return logrus.ErrorLevel
}
}
func defaultCallerFunc(callDepth int) *runtime.Frame {
pcs := make([]uintptr, 1)
_ = runtime.Callers(callDepth, pcs)
frames := runtime.CallersFrames(pcs)
frame, _ := frames.Next()
return &frame
}
// NewLogger create a log.Logger of name based on logrus.Logger.
func NewLogger(name string, out *logrus.Logger) log.Logger {
return log.NewStdLogger(name, NewOutPutter(out))
}
// MakeProvider make a log.LoggerProvider function.
func MakeProvider(out *logrus.Logger) log.LoggerProvider {
return func(name string) log.Logger {
return NewLogger(name, out)
}
}