blob: 337704457a2882ccf1117710acae90e2b3adb6c7 [file] [log] [blame]
kesavand2cde6582020-06-22 04:56:23 -04001package logrus
2
3import (
4 "context"
5 "io"
6 "os"
7 "sync"
8 "sync/atomic"
9 "time"
10)
11
kesavandc71914f2022-03-25 11:19:03 +053012// 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
15type LogFunction func() []interface{}
16
kesavand2cde6582020-06-22 04:56:23 -040017type 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}
48
49type exitFunc func(int)
50
51type MutexWrap struct {
52 lock sync.Mutex
53 disabled bool
54}
55
56func (mw *MutexWrap) Lock() {
57 if !mw.disabled {
58 mw.lock.Lock()
59 }
60}
61
62func (mw *MutexWrap) Unlock() {
63 if !mw.disabled {
64 mw.lock.Unlock()
65 }
66}
67
68func (mw *MutexWrap) Disable() {
69 mw.disabled = true
70}
71
72// Creates a new logger. Configuration should be set by changing `Formatter`,
73// `Out` and `Hooks` directly on the default logger instance. You can also just
74// instantiate your own:
75//
kesavandc71914f2022-03-25 11:19:03 +053076// var log = &logrus.Logger{
kesavand2cde6582020-06-22 04:56:23 -040077// Out: os.Stderr,
kesavandc71914f2022-03-25 11:19:03 +053078// Formatter: new(logrus.TextFormatter),
79// Hooks: make(logrus.LevelHooks),
kesavand2cde6582020-06-22 04:56:23 -040080// Level: logrus.DebugLevel,
81// }
82//
83// It's recommended to make this a global instance called `log`.
84func New() *Logger {
85 return &Logger{
86 Out: os.Stderr,
87 Formatter: new(TextFormatter),
88 Hooks: make(LevelHooks),
89 Level: InfoLevel,
90 ExitFunc: os.Exit,
91 ReportCaller: false,
92 }
93}
94
95func (logger *Logger) newEntry() *Entry {
96 entry, ok := logger.entryPool.Get().(*Entry)
97 if ok {
98 return entry
99 }
100 return NewEntry(logger)
101}
102
103func (logger *Logger) releaseEntry(entry *Entry) {
104 entry.Data = map[string]interface{}{}
105 logger.entryPool.Put(entry)
106}
107
kesavandc71914f2022-03-25 11:19:03 +0530108// WithField allocates a new entry and adds a field to it.
109// Debug, Print, Info, Warn, Error, Fatal or Panic must be then applied to
110// this new returned entry.
kesavand2cde6582020-06-22 04:56:23 -0400111// If you want multiple fields, use `WithFields`.
112func (logger *Logger) WithField(key string, value interface{}) *Entry {
113 entry := logger.newEntry()
114 defer logger.releaseEntry(entry)
115 return entry.WithField(key, value)
116}
117
118// Adds a struct of fields to the log entry. All it does is call `WithField` for
119// each `Field`.
120func (logger *Logger) WithFields(fields Fields) *Entry {
121 entry := logger.newEntry()
122 defer logger.releaseEntry(entry)
123 return entry.WithFields(fields)
124}
125
126// Add an error as single field to the log entry. All it does is call
127// `WithError` for the given `error`.
128func (logger *Logger) WithError(err error) *Entry {
129 entry := logger.newEntry()
130 defer logger.releaseEntry(entry)
131 return entry.WithError(err)
132}
133
134// Add a context to the log entry.
135func (logger *Logger) WithContext(ctx context.Context) *Entry {
136 entry := logger.newEntry()
137 defer logger.releaseEntry(entry)
138 return entry.WithContext(ctx)
139}
140
141// Overrides the time of the log entry.
142func (logger *Logger) WithTime(t time.Time) *Entry {
143 entry := logger.newEntry()
144 defer logger.releaseEntry(entry)
145 return entry.WithTime(t)
146}
147
148func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
149 if logger.IsLevelEnabled(level) {
150 entry := logger.newEntry()
151 entry.Logf(level, format, args...)
152 logger.releaseEntry(entry)
153 }
154}
155
156func (logger *Logger) Tracef(format string, args ...interface{}) {
157 logger.Logf(TraceLevel, format, args...)
158}
159
160func (logger *Logger) Debugf(format string, args ...interface{}) {
161 logger.Logf(DebugLevel, format, args...)
162}
163
164func (logger *Logger) Infof(format string, args ...interface{}) {
165 logger.Logf(InfoLevel, format, args...)
166}
167
168func (logger *Logger) Printf(format string, args ...interface{}) {
169 entry := logger.newEntry()
170 entry.Printf(format, args...)
171 logger.releaseEntry(entry)
172}
173
174func (logger *Logger) Warnf(format string, args ...interface{}) {
175 logger.Logf(WarnLevel, format, args...)
176}
177
178func (logger *Logger) Warningf(format string, args ...interface{}) {
179 logger.Warnf(format, args...)
180}
181
182func (logger *Logger) Errorf(format string, args ...interface{}) {
183 logger.Logf(ErrorLevel, format, args...)
184}
185
186func (logger *Logger) Fatalf(format string, args ...interface{}) {
187 logger.Logf(FatalLevel, format, args...)
188 logger.Exit(1)
189}
190
191func (logger *Logger) Panicf(format string, args ...interface{}) {
192 logger.Logf(PanicLevel, format, args...)
193}
194
195func (logger *Logger) Log(level Level, args ...interface{}) {
196 if logger.IsLevelEnabled(level) {
197 entry := logger.newEntry()
198 entry.Log(level, args...)
199 logger.releaseEntry(entry)
200 }
201}
202
kesavandc71914f2022-03-25 11:19:03 +0530203func (logger *Logger) LogFn(level Level, fn LogFunction) {
204 if logger.IsLevelEnabled(level) {
205 entry := logger.newEntry()
206 entry.Log(level, fn()...)
207 logger.releaseEntry(entry)
208 }
209}
210
kesavand2cde6582020-06-22 04:56:23 -0400211func (logger *Logger) Trace(args ...interface{}) {
212 logger.Log(TraceLevel, args...)
213}
214
215func (logger *Logger) Debug(args ...interface{}) {
216 logger.Log(DebugLevel, args...)
217}
218
219func (logger *Logger) Info(args ...interface{}) {
220 logger.Log(InfoLevel, args...)
221}
222
223func (logger *Logger) Print(args ...interface{}) {
224 entry := logger.newEntry()
225 entry.Print(args...)
226 logger.releaseEntry(entry)
227}
228
229func (logger *Logger) Warn(args ...interface{}) {
230 logger.Log(WarnLevel, args...)
231}
232
233func (logger *Logger) Warning(args ...interface{}) {
234 logger.Warn(args...)
235}
236
237func (logger *Logger) Error(args ...interface{}) {
238 logger.Log(ErrorLevel, args...)
239}
240
241func (logger *Logger) Fatal(args ...interface{}) {
242 logger.Log(FatalLevel, args...)
243 logger.Exit(1)
244}
245
246func (logger *Logger) Panic(args ...interface{}) {
247 logger.Log(PanicLevel, args...)
248}
249
kesavandc71914f2022-03-25 11:19:03 +0530250func (logger *Logger) TraceFn(fn LogFunction) {
251 logger.LogFn(TraceLevel, fn)
252}
253
254func (logger *Logger) DebugFn(fn LogFunction) {
255 logger.LogFn(DebugLevel, fn)
256}
257
258func (logger *Logger) InfoFn(fn LogFunction) {
259 logger.LogFn(InfoLevel, fn)
260}
261
262func (logger *Logger) PrintFn(fn LogFunction) {
263 entry := logger.newEntry()
264 entry.Print(fn()...)
265 logger.releaseEntry(entry)
266}
267
268func (logger *Logger) WarnFn(fn LogFunction) {
269 logger.LogFn(WarnLevel, fn)
270}
271
272func (logger *Logger) WarningFn(fn LogFunction) {
273 logger.WarnFn(fn)
274}
275
276func (logger *Logger) ErrorFn(fn LogFunction) {
277 logger.LogFn(ErrorLevel, fn)
278}
279
280func (logger *Logger) FatalFn(fn LogFunction) {
281 logger.LogFn(FatalLevel, fn)
282 logger.Exit(1)
283}
284
285func (logger *Logger) PanicFn(fn LogFunction) {
286 logger.LogFn(PanicLevel, fn)
287}
288
kesavand2cde6582020-06-22 04:56:23 -0400289func (logger *Logger) Logln(level Level, args ...interface{}) {
290 if logger.IsLevelEnabled(level) {
291 entry := logger.newEntry()
292 entry.Logln(level, args...)
293 logger.releaseEntry(entry)
294 }
295}
296
297func (logger *Logger) Traceln(args ...interface{}) {
298 logger.Logln(TraceLevel, args...)
299}
300
301func (logger *Logger) Debugln(args ...interface{}) {
302 logger.Logln(DebugLevel, args...)
303}
304
305func (logger *Logger) Infoln(args ...interface{}) {
306 logger.Logln(InfoLevel, args...)
307}
308
309func (logger *Logger) Println(args ...interface{}) {
310 entry := logger.newEntry()
311 entry.Println(args...)
312 logger.releaseEntry(entry)
313}
314
315func (logger *Logger) Warnln(args ...interface{}) {
316 logger.Logln(WarnLevel, args...)
317}
318
319func (logger *Logger) Warningln(args ...interface{}) {
320 logger.Warnln(args...)
321}
322
323func (logger *Logger) Errorln(args ...interface{}) {
324 logger.Logln(ErrorLevel, args...)
325}
326
327func (logger *Logger) Fatalln(args ...interface{}) {
328 logger.Logln(FatalLevel, args...)
329 logger.Exit(1)
330}
331
332func (logger *Logger) Panicln(args ...interface{}) {
333 logger.Logln(PanicLevel, args...)
334}
335
336func (logger *Logger) Exit(code int) {
337 runHandlers()
338 if logger.ExitFunc == nil {
339 logger.ExitFunc = os.Exit
340 }
341 logger.ExitFunc(code)
342}
343
344//When file is opened with appending mode, it's safe to
345//write concurrently to a file (within 4k message on Linux).
346//In these cases user can choose to disable the lock.
347func (logger *Logger) SetNoLock() {
348 logger.mu.Disable()
349}
350
351func (logger *Logger) level() Level {
352 return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
353}
354
355// SetLevel sets the logger level.
356func (logger *Logger) SetLevel(level Level) {
357 atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
358}
359
360// GetLevel returns the logger level.
361func (logger *Logger) GetLevel() Level {
362 return logger.level()
363}
364
365// AddHook adds a hook to the logger hooks.
366func (logger *Logger) AddHook(hook Hook) {
367 logger.mu.Lock()
368 defer logger.mu.Unlock()
369 logger.Hooks.Add(hook)
370}
371
372// IsLevelEnabled checks if the log level of the logger is greater than the level param
373func (logger *Logger) IsLevelEnabled(level Level) bool {
374 return logger.level() >= level
375}
376
377// SetFormatter sets the logger formatter.
378func (logger *Logger) SetFormatter(formatter Formatter) {
379 logger.mu.Lock()
380 defer logger.mu.Unlock()
381 logger.Formatter = formatter
382}
383
384// SetOutput sets the logger output.
385func (logger *Logger) SetOutput(output io.Writer) {
386 logger.mu.Lock()
387 defer logger.mu.Unlock()
388 logger.Out = output
389}
390
391func (logger *Logger) SetReportCaller(reportCaller bool) {
392 logger.mu.Lock()
393 defer logger.mu.Unlock()
394 logger.ReportCaller = reportCaller
395}
396
397// ReplaceHooks replaces the logger hooks and returns the old ones
398func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
399 logger.mu.Lock()
400 oldHooks := logger.Hooks
401 logger.Hooks = hooks
402 logger.mu.Unlock()
403 return oldHooks
404}