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
package logging
import (
"sync"
"github.com/sirupsen/logrus"
)
// Logger is the interface to our internal logger.
type Logger interface {
Debug(msg string, kvpairs ...interface{})
Info(msg string, kvpairs ...interface{})
Error(msg string, kvpairs ...interface{})
SetField(key string, val interface{})
PushFields()
PopFields()
}
// LogrusLogger is a thread-safe logger whose properties persist and can be modified.
type LogrusLogger struct {
mtx sync.Mutex
logger *logrus.Entry
ctx string
fields map[string]interface{}
pushedFieldSets []map[string]interface{}
}
// NoopLogger implements Logger, but does nothing.
type NoopLogger struct{}
// LogrusLogger implements Logger
var _ Logger = (*LogrusLogger)(nil)
var _ Logger = (*NoopLogger)(nil)
//
// LogrusLogger
//
// NewLogrusLogger will instantiate a logger with the given context.
func NewLogrusLogger(ctx string, kvpairs ...interface{}) Logger {
var logger *logrus.Entry
if len(ctx) > 0 {
logger = logrus.WithField("ctx", ctx)
} else {
logger = logrus.NewEntry(logrus.New())
}
return &LogrusLogger{
logger: logger,
ctx: ctx,
fields: serializeKVPairs(kvpairs),
pushedFieldSets: []map[string]interface{}{},
}
}
func (l *LogrusLogger) withFields() *logrus.Entry {
if len(l.fields) > 0 {
return l.logger.WithFields(l.fields)
}
return l.logger
}
func serializeKVPairs(kvpairs ...interface{}) map[string]interface{} {
res := make(map[string]interface{})
if (len(kvpairs) % 2) == 0 {
for i := 0; i < len(kvpairs); i += 2 {
res[kvpairs[i].(string)] = kvpairs[i+1]
}
}
return res
}
func (l *LogrusLogger) withKVPairs(kvpairs ...interface{}) *logrus.Entry {
fields := serializeKVPairs(kvpairs...)
if len(fields) > 0 {
return l.withFields().WithFields(fields)
}
return l.withFields()
}
func (l *LogrusLogger) Debug(msg string, kvpairs ...interface{}) {
l.mtx.Lock()
defer l.mtx.Unlock()
l.withKVPairs(kvpairs...).Debugln(msg)
}
func (l *LogrusLogger) Info(msg string, kvpairs ...interface{}) {
l.mtx.Lock()
defer l.mtx.Unlock()
l.withKVPairs(kvpairs...).Infoln(msg)
}
func (l *LogrusLogger) Error(msg string, kvpairs ...interface{}) {
l.mtx.Lock()
defer l.mtx.Unlock()
l.withKVPairs(kvpairs...).Errorln(msg)
}
func (l *LogrusLogger) SetField(key string, val interface{}) {
l.mtx.Lock()
defer l.mtx.Unlock()
l.fields[key] = val
}
func (l *LogrusLogger) PushFields() {
l.mtx.Lock()
defer l.mtx.Unlock()
l.pushedFieldSets = append(l.pushedFieldSets, l.fields)
}
func (l *LogrusLogger) PopFields() {
l.mtx.Lock()
defer l.mtx.Unlock()
pfsLen := len(l.pushedFieldSets)
if pfsLen > 0 {
l.fields = l.pushedFieldSets[pfsLen-1]
l.pushedFieldSets = l.pushedFieldSets[:pfsLen-1]
}
}
//
// NoopLogger
//
// NewNoopLogger will instantiate a logger that does nothing when called.
func NewNoopLogger() Logger {
return &NoopLogger{}
}
func (l *NoopLogger) Debug(msg string, kvpairs ...interface{}) {}
func (l *NoopLogger) Info(msg string, kvpairs ...interface{}) {}
func (l *NoopLogger) Error(msg string, kvpairs ...interface{}) {}
func (l *NoopLogger) SetField(key string, val interface{}) {}
func (l *NoopLogger) PushFields() {}
func (l *NoopLogger) PopFields() {}