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