-
Notifications
You must be signed in to change notification settings - Fork 4
/
leveled_logger.go
303 lines (257 loc) · 9.34 KB
/
leveled_logger.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
package log
import (
"fmt"
"io"
"log"
"os"
"sync/atomic"
)
// NewLeveledLogger creates a LeveledLogger with given output writer and flag.
// The flag argument defines the logging properties, it is the same as log.New.
// You could use flags from THIS log package to avoid importing standard package log.
func NewLeveledLogger(out io.Writer, flag int) *LeveledLogger {
return NewLeveledLoggerWithColor(out, flag, IsTerminal(out))
}
// NewLeveledLoggerWithColor is NewLeveledLogger with an additional colored parameter indicating if color is forced.
func NewLeveledLoggerWithColor(out io.Writer, flag int, colored bool) *LeveledLogger {
return &LeveledLogger{
debug: log.New(out, tryPaint("D ", ColorBlue, colored), flag),
info: log.New(out, tryPaint("I ", ColorGreen, colored), flag),
warn: log.New(out, tryPaint("W ", ColorYellow, colored), flag),
erro: log.New(out, tryPaint("E ", ColorMegenta, colored), flag),
fata: log.New(out, tryPaint("F ", ColorRed, colored), flag),
defaultLevel: INFO,
outputLevel: NOTSET,
depth: 3,
}
}
func tryPaint(str string, color string, colored bool) string {
if !colored {
return str
}
return paint(str, color)
}
// LeveledLogger has the ability of logging with different levels.
type LeveledLogger struct {
debug *log.Logger
info *log.Logger
warn *log.Logger
erro *log.Logger
fata *log.Logger
outputLevel Level
defaultLevel Level
depth int
}
// SetDefaultLevel sets the DefaultLevel atomically.
func (l *LeveledLogger) SetDefaultLevel(level Level) {
atomic.StoreInt32((*int32)(&l.defaultLevel), int32(level))
}
// DefaultLevel is the level used by Print* methods.
func (l *LeveledLogger) DefaultLevel() Level {
return Level(atomic.LoadInt32((*int32)(&l.defaultLevel)))
}
// SetOutputLevel sets the OutputLevel atomically.
func (l *LeveledLogger) SetOutputLevel(level Level) {
atomic.StoreInt32((*int32)(&l.outputLevel), int32(level))
}
// OutputLevel returns the minimal Level of log that will be outputted.
// Levels lower than this will be ignored.
func (l *LeveledLogger) OutputLevel() Level {
return Level(atomic.LoadInt32((*int32)(&l.outputLevel)))
}
// SetCallerOffset sets the offset used in runtime.Caller(3 + offset)
// while getting file name and line number.
// NOTE: Do not call this while logging, it's not goroutine safe.
func (l *LeveledLogger) SetCallerOffset(offset int) {
l.depth = offset + 3
}
// Print prints log with DefaultLevel.
// Arguments are handled in the manner of fmt.Print.
func (l *LeveledLogger) Print(a ...interface{}) {
l.output(l.DefaultLevel(), a...)
}
// Printf prints log with DefaultLevel.
// Arguments are handled in the manner of fmt.Printf.
func (l *LeveledLogger) Printf(format string, a ...interface{}) {
l.outputf(l.DefaultLevel(), format, a...)
}
// Println prints log with DefaultLevel.
// Arguments are handled in the manner of fmt.Println.
func (l *LeveledLogger) Println(a ...interface{}) {
l.outputln(l.DefaultLevel(), a...)
}
// PrintDepth acts as Print but uses depth to determine which call frame to log
// PrintDepth(0, "msg") is the same as Print("msg")
func (l *LeveledLogger) PrintDepth(depth int, a ...interface{}) {
l.outputDepth(depth, l.DefaultLevel(), a...)
}
// PrintfDepth acts as Printf but uses depth to determine which call frame to log
// PrintfDepth(0, "msg") is the same as Printf("msg")
func (l *LeveledLogger) PrintfDepth(depth int, format string, a ...interface{}) {
l.outputfDepth(depth, l.DefaultLevel(), format, a...)
}
// PrintlnDepth acts as Printfln but uses depth to determine which call frame to log
// PrintflnDepth(0, "msg") is the same as Printfln("msg")
func (l *LeveledLogger) PrintlnDepth(depth int, a ...interface{}) {
l.outputlnDepth(depth, l.DefaultLevel(), a...)
}
// Debug prints log with level DEBUG.
// Arguments are handled in the manner of fmt.Print.
func (l *LeveledLogger) Debug(a ...interface{}) {
l.output(DEBUG, a...)
}
// Debugf prints log with level DEBUG.
// Arguments are handled in the manner of fmt.Printf.
func (l *LeveledLogger) Debugf(format string, a ...interface{}) {
l.outputf(DEBUG, format, a...)
}
// DebugDepth acts as Debug but uses depth to determine which call frame to log
// DebugDepth(0, "msg") is the same as Debug("msg")
func (l *LeveledLogger) DebugDepth(depth int, a ...interface{}) {
l.outputDepth(depth, DEBUG, a...)
}
// DebugfDepth acts as Debugf but uses depth to determine which call frame to log
// DebugfDepth(0, "msg") is the same as Debugf("msg")
func (l *LeveledLogger) DebugfDepth(depth int, format string, a ...interface{}) {
l.outputfDepth(depth, DEBUG, format, a...)
}
// Info prints log with level INFO.
// Arguments are handled in the manner of fmt.Print.
func (l *LeveledLogger) Info(a ...interface{}) {
l.output(INFO, a...)
}
// Infof prints log with level INFO.
// Arguments are handled in the manner of fmt.Printf.
func (l *LeveledLogger) Infof(format string, a ...interface{}) {
l.outputf(INFO, format, a...)
}
// InfoDepth acts as Info but uses depth to determine which call frame to log
// InfoDepth(0, "msg") is the same as Info("msg")
func (l *LeveledLogger) InfoDepth(depth int, a ...interface{}) {
l.outputDepth(depth, INFO, a...)
}
// InfofDepth acts as Infof but uses depth to determine which call frame to log
// InfofDepth(0, "msg") is the same as Infof("msg")
func (l *LeveledLogger) InfofDepth(depth int, format string, a ...interface{}) {
l.outputfDepth(depth, INFO, format, a...)
}
// Warn prints log with level WARN.
// Arguments are handled in the manner of fmt.Print.
func (l *LeveledLogger) Warn(a ...interface{}) {
l.output(WARN, a...)
}
// Warnf prints log with level WARN.
// Arguments are handled in the manner of fmt.Printf.
func (l *LeveledLogger) Warnf(format string, a ...interface{}) {
l.outputf(WARN, format, a...)
}
// WarnDepth acts as Warn but uses depth to determine which call frame to log
// WarnDepth(0, "msg") is the same as Warn("msg")
func (l *LeveledLogger) WarnDepth(depth int, a ...interface{}) {
l.outputDepth(depth, WARN, a...)
}
// WarnfDepth acts as Warnf but uses depth to determine which call frame to log
// WarnfDepth(0, "msg") is the same as Warnf("msg")
func (l *LeveledLogger) WarnfDepth(depth int, format string, a ...interface{}) {
l.outputfDepth(depth, WARN, format, a...)
}
// Error prints log with level ERROR.
// Arguments are handled in the manner of fmt.Print.
func (l *LeveledLogger) Error(a ...interface{}) {
l.output(ERROR, a...)
}
// Errorf prints log with level ERROR.
// Arguments are handled in the manner of fmt.Printf.
func (l *LeveledLogger) Errorf(format string, a ...interface{}) {
l.outputf(ERROR, format, a...)
}
// ErrorDepth acts as Error but uses depth to determine which call frame to log
// ErrorDepth(0, "msg") is the same as Error("msg")
func (l *LeveledLogger) ErrorDepth(depth int, a ...interface{}) {
l.outputDepth(depth, ERROR, a...)
}
// ErrorfDepth acts as Errorf but uses depth to determine which call frame to log
// ErrorfDepth(0, "msg") is the same as Errorf("msg")
func (l *LeveledLogger) ErrorfDepth(depth int, format string, a ...interface{}) {
l.outputfDepth(depth, ERROR, format, a...)
}
// Fatal prints log with level FATA then os.Exit(1).
// Arguments are handled in the manner of fmt.Print.
func (l *LeveledLogger) Fatal(a ...interface{}) {
l.output(FATA, a...)
}
// Fatalf prints log with level FATA then os.Exit(1).
// Arguments are handled in the manner of fmt.Printf.
func (l *LeveledLogger) Fatalf(format string, a ...interface{}) {
l.outputf(FATA, format, a...)
}
// FatalDepth acts as Fatal but uses depth to determine which call frame to log
// FatalDepth(0, "msg") is the same as Fatal("msg")
func (l *LeveledLogger) FatalDepth(depth int, a ...interface{}) {
l.outputDepth(depth, FATA, a...)
}
// FatalfDepth acts as Fatalf but uses depth to determine which call frame to log
// FatalfDepth(0, "msg") is the same as Fatalf("msg")
func (l *LeveledLogger) FatalfDepth(depth int, format string, a ...interface{}) {
l.outputfDepth(depth, FATA, format, a...)
}
func (l *LeveledLogger) output(level Level, a ...interface{}) {
l.outputDepth(1, level, a...)
}
func (l *LeveledLogger) outputDepth(depth int, level Level, a ...interface{}) {
if level < l.OutputLevel() {
return
}
logger := l.getOutputTarget(level)
if logger != nil {
logger.Output(l.depth+depth, fmt.Sprint(a...))
}
if level == FATA {
os.Exit(1)
}
}
func (l *LeveledLogger) outputln(level Level, a ...interface{}) {
l.outputlnDepth(1, level, a...)
}
func (l *LeveledLogger) outputlnDepth(depth int, level Level, a ...interface{}) {
if level < l.OutputLevel() {
return
}
logger := l.getOutputTarget(level)
if logger != nil {
logger.Output(l.depth+depth, fmt.Sprintln(a...))
}
if level == FATA {
os.Exit(1)
}
}
func (l *LeveledLogger) outputf(level Level, format string, a ...interface{}) {
l.outputfDepth(1, level, format, a...)
}
func (l *LeveledLogger) outputfDepth(depth int, level Level, format string, a ...interface{}) {
if level < l.OutputLevel() {
return
}
logger := l.getOutputTarget(level)
if logger != nil {
logger.Output(l.depth+depth, fmt.Sprintf(format, a...))
}
if level == FATA {
os.Exit(1)
}
}
func (l *LeveledLogger) getOutputTarget(level Level) (logger *log.Logger) {
switch level {
case DEBUG:
logger = l.debug
case INFO:
logger = l.info
case WARN:
logger = l.warn
case ERROR:
logger = l.erro
case FATA:
logger = l.fata
}
return
}