66
|
1 package logrus
|
|
2
|
|
3 import (
|
|
4 "context"
|
|
5 "io"
|
|
6 "os"
|
|
7 "sync"
|
|
8 "sync/atomic"
|
|
9 "time"
|
|
10 )
|
|
11
|
|
12 // LogFunction For big messages, it can be more efficient to pass a function
|
|
13 // and only call it if the log level is actually enables rather than
|
|
14 // generating the log message and then checking if the level is enabled
|
|
15 type LogFunction func() []interface{}
|
|
16
|
|
17 type Logger struct {
|
|
18 // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
|
19 // file, or leave it default which is `os.Stderr`. You can also set this to
|
|
20 // something more adventurous, such as logging to Kafka.
|
|
21 Out io.Writer
|
|
22 // Hooks for the logger instance. These allow firing events based on logging
|
|
23 // levels and log entries. For example, to send errors to an error tracking
|
|
24 // service, log to StatsD or dump the core on fatal errors.
|
|
25 Hooks LevelHooks
|
|
26 // All log entries pass through the formatter before logged to Out. The
|
|
27 // included formatters are `TextFormatter` and `JSONFormatter` for which
|
|
28 // TextFormatter is the default. In development (when a TTY is attached) it
|
|
29 // logs with colors, but to a file it wouldn't. You can easily implement your
|
|
30 // own that implements the `Formatter` interface, see the `README` or included
|
|
31 // formatters for examples.
|
|
32 Formatter Formatter
|
|
33
|
|
34 // Flag for whether to log caller info (off by default)
|
|
35 ReportCaller bool
|
|
36
|
|
37 // The logging level the logger should log at. This is typically (and defaults
|
|
38 // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
|
39 // logged.
|
|
40 Level Level
|
|
41 // Used to sync writing to the log. Locking is enabled by Default
|
|
42 mu MutexWrap
|
|
43 // Reusable empty entry
|
|
44 entryPool sync.Pool
|
|
45 // Function to exit the application, defaults to `os.Exit()`
|
|
46 ExitFunc exitFunc
|
|
47 // The buffer pool used to format the log. If it is nil, the default global
|
|
48 // buffer pool will be used.
|
|
49 BufferPool BufferPool
|
|
50 }
|
|
51
|
|
52 type exitFunc func(int)
|
|
53
|
|
54 type MutexWrap struct {
|
|
55 lock sync.Mutex
|
|
56 disabled bool
|
|
57 }
|
|
58
|
|
59 func (mw *MutexWrap) Lock() {
|
|
60 if !mw.disabled {
|
|
61 mw.lock.Lock()
|
|
62 }
|
|
63 }
|
|
64
|
|
65 func (mw *MutexWrap) Unlock() {
|
|
66 if !mw.disabled {
|
|
67 mw.lock.Unlock()
|
|
68 }
|
|
69 }
|
|
70
|
|
71 func (mw *MutexWrap) Disable() {
|
|
72 mw.disabled = true
|
|
73 }
|
|
74
|
|
75 // Creates a new logger. Configuration should be set by changing `Formatter`,
|
|
76 // `Out` and `Hooks` directly on the default logger instance. You can also just
|
|
77 // instantiate your own:
|
|
78 //
|
|
79 // var log = &logrus.Logger{
|
|
80 // Out: os.Stderr,
|
|
81 // Formatter: new(logrus.TextFormatter),
|
|
82 // Hooks: make(logrus.LevelHooks),
|
|
83 // Level: logrus.DebugLevel,
|
|
84 // }
|
|
85 //
|
|
86 // It's recommended to make this a global instance called `log`.
|
|
87 func New() *Logger {
|
|
88 return &Logger{
|
|
89 Out: os.Stderr,
|
|
90 Formatter: new(TextFormatter),
|
|
91 Hooks: make(LevelHooks),
|
|
92 Level: InfoLevel,
|
|
93 ExitFunc: os.Exit,
|
|
94 ReportCaller: false,
|
|
95 }
|
|
96 }
|
|
97
|
|
98 func (logger *Logger) newEntry() *Entry {
|
|
99 entry, ok := logger.entryPool.Get().(*Entry)
|
|
100 if ok {
|
|
101 return entry
|
|
102 }
|
|
103 return NewEntry(logger)
|
|
104 }
|
|
105
|
|
106 func (logger *Logger) releaseEntry(entry *Entry) {
|
|
107 entry.Data = map[string]interface{}{}
|
|
108 logger.entryPool.Put(entry)
|
|
109 }
|
|
110
|
|
111 // WithField allocates a new entry and adds a field to it.
|
|
112 // Debug, Print, Info, Warn, Error, Fatal or Panic must be then applied to
|
|
113 // this new returned entry.
|
|
114 // If you want multiple fields, use `WithFields`.
|
|
115 func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
|
116 entry := logger.newEntry()
|
|
117 defer logger.releaseEntry(entry)
|
|
118 return entry.WithField(key, value)
|
|
119 }
|
|
120
|
|
121 // Adds a struct of fields to the log entry. All it does is call `WithField` for
|
|
122 // each `Field`.
|
|
123 func (logger *Logger) WithFields(fields Fields) *Entry {
|
|
124 entry := logger.newEntry()
|
|
125 defer logger.releaseEntry(entry)
|
|
126 return entry.WithFields(fields)
|
|
127 }
|
|
128
|
|
129 // Add an error as single field to the log entry. All it does is call
|
|
130 // `WithError` for the given `error`.
|
|
131 func (logger *Logger) WithError(err error) *Entry {
|
|
132 entry := logger.newEntry()
|
|
133 defer logger.releaseEntry(entry)
|
|
134 return entry.WithError(err)
|
|
135 }
|
|
136
|
|
137 // Add a context to the log entry.
|
|
138 func (logger *Logger) WithContext(ctx context.Context) *Entry {
|
|
139 entry := logger.newEntry()
|
|
140 defer logger.releaseEntry(entry)
|
|
141 return entry.WithContext(ctx)
|
|
142 }
|
|
143
|
|
144 // Overrides the time of the log entry.
|
|
145 func (logger *Logger) WithTime(t time.Time) *Entry {
|
|
146 entry := logger.newEntry()
|
|
147 defer logger.releaseEntry(entry)
|
|
148 return entry.WithTime(t)
|
|
149 }
|
|
150
|
|
151 func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
|
|
152 if logger.IsLevelEnabled(level) {
|
|
153 entry := logger.newEntry()
|
|
154 entry.Logf(level, format, args...)
|
|
155 logger.releaseEntry(entry)
|
|
156 }
|
|
157 }
|
|
158
|
|
159 func (logger *Logger) Tracef(format string, args ...interface{}) {
|
|
160 logger.Logf(TraceLevel, format, args...)
|
|
161 }
|
|
162
|
|
163 func (logger *Logger) Debugf(format string, args ...interface{}) {
|
|
164 logger.Logf(DebugLevel, format, args...)
|
|
165 }
|
|
166
|
|
167 func (logger *Logger) Infof(format string, args ...interface{}) {
|
|
168 logger.Logf(InfoLevel, format, args...)
|
|
169 }
|
|
170
|
|
171 func (logger *Logger) Printf(format string, args ...interface{}) {
|
|
172 entry := logger.newEntry()
|
|
173 entry.Printf(format, args...)
|
|
174 logger.releaseEntry(entry)
|
|
175 }
|
|
176
|
|
177 func (logger *Logger) Warnf(format string, args ...interface{}) {
|
|
178 logger.Logf(WarnLevel, format, args...)
|
|
179 }
|
|
180
|
|
181 func (logger *Logger) Warningf(format string, args ...interface{}) {
|
|
182 logger.Warnf(format, args...)
|
|
183 }
|
|
184
|
|
185 func (logger *Logger) Errorf(format string, args ...interface{}) {
|
|
186 logger.Logf(ErrorLevel, format, args...)
|
|
187 }
|
|
188
|
|
189 func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
|
190 logger.Logf(FatalLevel, format, args...)
|
|
191 logger.Exit(1)
|
|
192 }
|
|
193
|
|
194 func (logger *Logger) Panicf(format string, args ...interface{}) {
|
|
195 logger.Logf(PanicLevel, format, args...)
|
|
196 }
|
|
197
|
|
198 // Log will log a message at the level given as parameter.
|
|
199 // Warning: using Log at Panic or Fatal level will not respectively Panic nor Exit.
|
|
200 // For this behaviour Logger.Panic or Logger.Fatal should be used instead.
|
|
201 func (logger *Logger) Log(level Level, args ...interface{}) {
|
|
202 if logger.IsLevelEnabled(level) {
|
|
203 entry := logger.newEntry()
|
|
204 entry.Log(level, args...)
|
|
205 logger.releaseEntry(entry)
|
|
206 }
|
|
207 }
|
|
208
|
|
209 func (logger *Logger) LogFn(level Level, fn LogFunction) {
|
|
210 if logger.IsLevelEnabled(level) {
|
|
211 entry := logger.newEntry()
|
|
212 entry.Log(level, fn()...)
|
|
213 logger.releaseEntry(entry)
|
|
214 }
|
|
215 }
|
|
216
|
|
217 func (logger *Logger) Trace(args ...interface{}) {
|
|
218 logger.Log(TraceLevel, args...)
|
|
219 }
|
|
220
|
|
221 func (logger *Logger) Debug(args ...interface{}) {
|
|
222 logger.Log(DebugLevel, args...)
|
|
223 }
|
|
224
|
|
225 func (logger *Logger) Info(args ...interface{}) {
|
|
226 logger.Log(InfoLevel, args...)
|
|
227 }
|
|
228
|
|
229 func (logger *Logger) Print(args ...interface{}) {
|
|
230 entry := logger.newEntry()
|
|
231 entry.Print(args...)
|
|
232 logger.releaseEntry(entry)
|
|
233 }
|
|
234
|
|
235 func (logger *Logger) Warn(args ...interface{}) {
|
|
236 logger.Log(WarnLevel, args...)
|
|
237 }
|
|
238
|
|
239 func (logger *Logger) Warning(args ...interface{}) {
|
|
240 logger.Warn(args...)
|
|
241 }
|
|
242
|
|
243 func (logger *Logger) Error(args ...interface{}) {
|
|
244 logger.Log(ErrorLevel, args...)
|
|
245 }
|
|
246
|
|
247 func (logger *Logger) Fatal(args ...interface{}) {
|
|
248 logger.Log(FatalLevel, args...)
|
|
249 logger.Exit(1)
|
|
250 }
|
|
251
|
|
252 func (logger *Logger) Panic(args ...interface{}) {
|
|
253 logger.Log(PanicLevel, args...)
|
|
254 }
|
|
255
|
|
256 func (logger *Logger) TraceFn(fn LogFunction) {
|
|
257 logger.LogFn(TraceLevel, fn)
|
|
258 }
|
|
259
|
|
260 func (logger *Logger) DebugFn(fn LogFunction) {
|
|
261 logger.LogFn(DebugLevel, fn)
|
|
262 }
|
|
263
|
|
264 func (logger *Logger) InfoFn(fn LogFunction) {
|
|
265 logger.LogFn(InfoLevel, fn)
|
|
266 }
|
|
267
|
|
268 func (logger *Logger) PrintFn(fn LogFunction) {
|
|
269 entry := logger.newEntry()
|
|
270 entry.Print(fn()...)
|
|
271 logger.releaseEntry(entry)
|
|
272 }
|
|
273
|
|
274 func (logger *Logger) WarnFn(fn LogFunction) {
|
|
275 logger.LogFn(WarnLevel, fn)
|
|
276 }
|
|
277
|
|
278 func (logger *Logger) WarningFn(fn LogFunction) {
|
|
279 logger.WarnFn(fn)
|
|
280 }
|
|
281
|
|
282 func (logger *Logger) ErrorFn(fn LogFunction) {
|
|
283 logger.LogFn(ErrorLevel, fn)
|
|
284 }
|
|
285
|
|
286 func (logger *Logger) FatalFn(fn LogFunction) {
|
|
287 logger.LogFn(FatalLevel, fn)
|
|
288 logger.Exit(1)
|
|
289 }
|
|
290
|
|
291 func (logger *Logger) PanicFn(fn LogFunction) {
|
|
292 logger.LogFn(PanicLevel, fn)
|
|
293 }
|
|
294
|
|
295 func (logger *Logger) Logln(level Level, args ...interface{}) {
|
|
296 if logger.IsLevelEnabled(level) {
|
|
297 entry := logger.newEntry()
|
|
298 entry.Logln(level, args...)
|
|
299 logger.releaseEntry(entry)
|
|
300 }
|
|
301 }
|
|
302
|
|
303 func (logger *Logger) Traceln(args ...interface{}) {
|
|
304 logger.Logln(TraceLevel, args...)
|
|
305 }
|
|
306
|
|
307 func (logger *Logger) Debugln(args ...interface{}) {
|
|
308 logger.Logln(DebugLevel, args...)
|
|
309 }
|
|
310
|
|
311 func (logger *Logger) Infoln(args ...interface{}) {
|
|
312 logger.Logln(InfoLevel, args...)
|
|
313 }
|
|
314
|
|
315 func (logger *Logger) Println(args ...interface{}) {
|
|
316 entry := logger.newEntry()
|
|
317 entry.Println(args...)
|
|
318 logger.releaseEntry(entry)
|
|
319 }
|
|
320
|
|
321 func (logger *Logger) Warnln(args ...interface{}) {
|
|
322 logger.Logln(WarnLevel, args...)
|
|
323 }
|
|
324
|
|
325 func (logger *Logger) Warningln(args ...interface{}) {
|
|
326 logger.Warnln(args...)
|
|
327 }
|
|
328
|
|
329 func (logger *Logger) Errorln(args ...interface{}) {
|
|
330 logger.Logln(ErrorLevel, args...)
|
|
331 }
|
|
332
|
|
333 func (logger *Logger) Fatalln(args ...interface{}) {
|
|
334 logger.Logln(FatalLevel, args...)
|
|
335 logger.Exit(1)
|
|
336 }
|
|
337
|
|
338 func (logger *Logger) Panicln(args ...interface{}) {
|
|
339 logger.Logln(PanicLevel, args...)
|
|
340 }
|
|
341
|
|
342 func (logger *Logger) Exit(code int) {
|
|
343 runHandlers()
|
|
344 if logger.ExitFunc == nil {
|
|
345 logger.ExitFunc = os.Exit
|
|
346 }
|
|
347 logger.ExitFunc(code)
|
|
348 }
|
|
349
|
|
350 //When file is opened with appending mode, it's safe to
|
|
351 //write concurrently to a file (within 4k message on Linux).
|
|
352 //In these cases user can choose to disable the lock.
|
|
353 func (logger *Logger) SetNoLock() {
|
|
354 logger.mu.Disable()
|
|
355 }
|
|
356
|
|
357 func (logger *Logger) level() Level {
|
|
358 return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
|
359 }
|
|
360
|
|
361 // SetLevel sets the logger level.
|
|
362 func (logger *Logger) SetLevel(level Level) {
|
|
363 atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
|
364 }
|
|
365
|
|
366 // GetLevel returns the logger level.
|
|
367 func (logger *Logger) GetLevel() Level {
|
|
368 return logger.level()
|
|
369 }
|
|
370
|
|
371 // AddHook adds a hook to the logger hooks.
|
|
372 func (logger *Logger) AddHook(hook Hook) {
|
|
373 logger.mu.Lock()
|
|
374 defer logger.mu.Unlock()
|
|
375 logger.Hooks.Add(hook)
|
|
376 }
|
|
377
|
|
378 // IsLevelEnabled checks if the log level of the logger is greater than the level param
|
|
379 func (logger *Logger) IsLevelEnabled(level Level) bool {
|
|
380 return logger.level() >= level
|
|
381 }
|
|
382
|
|
383 // SetFormatter sets the logger formatter.
|
|
384 func (logger *Logger) SetFormatter(formatter Formatter) {
|
|
385 logger.mu.Lock()
|
|
386 defer logger.mu.Unlock()
|
|
387 logger.Formatter = formatter
|
|
388 }
|
|
389
|
|
390 // SetOutput sets the logger output.
|
|
391 func (logger *Logger) SetOutput(output io.Writer) {
|
|
392 logger.mu.Lock()
|
|
393 defer logger.mu.Unlock()
|
|
394 logger.Out = output
|
|
395 }
|
|
396
|
|
397 func (logger *Logger) SetReportCaller(reportCaller bool) {
|
|
398 logger.mu.Lock()
|
|
399 defer logger.mu.Unlock()
|
|
400 logger.ReportCaller = reportCaller
|
|
401 }
|
|
402
|
|
403 // ReplaceHooks replaces the logger hooks and returns the old ones
|
|
404 func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
|
|
405 logger.mu.Lock()
|
|
406 oldHooks := logger.Hooks
|
|
407 logger.Hooks = hooks
|
|
408 logger.mu.Unlock()
|
|
409 return oldHooks
|
|
410 }
|
|
411
|
|
412 // SetBufferPool sets the logger buffer pool.
|
|
413 func (logger *Logger) SetBufferPool(pool BufferPool) {
|
|
414 logger.mu.Lock()
|
|
415 defer logger.mu.Unlock()
|
|
416 logger.BufferPool = pool
|
|
417 }
|