blob: 5ff0aef6d3f1f98f432a8173cfd868faef485342 [file] [log] [blame]
khenaidoo59ce9dd2019-11-11 13:05:32 -05001package logrus
2
3import (
khenaidoo26721882021-08-11 17:42:52 -04004 "context"
khenaidoo59ce9dd2019-11-11 13:05:32 -05005 "io"
6 "os"
7 "sync"
8 "sync/atomic"
9 "time"
10)
11
Abhay Kumar40252eb2025-10-13 13:25:53 +000012// 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
khenaidoo59ce9dd2019-11-11 13:05:32 -050017type 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
Abhay Kumar40252eb2025-10-13 13:25:53 +000047 // The buffer pool used to format the log. If it is nil, the default global
48 // buffer pool will be used.
49 BufferPool BufferPool
khenaidoo59ce9dd2019-11-11 13:05:32 -050050}
51
52type exitFunc func(int)
53
54type MutexWrap struct {
55 lock sync.Mutex
56 disabled bool
57}
58
59func (mw *MutexWrap) Lock() {
60 if !mw.disabled {
61 mw.lock.Lock()
62 }
63}
64
65func (mw *MutexWrap) Unlock() {
66 if !mw.disabled {
67 mw.lock.Unlock()
68 }
69}
70
71func (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//
khenaidoo26721882021-08-11 17:42:52 -040079// var log = &logrus.Logger{
khenaidoo59ce9dd2019-11-11 13:05:32 -050080// Out: os.Stderr,
Abhay Kumar40252eb2025-10-13 13:25:53 +000081// Formatter: new(logrus.TextFormatter),
khenaidoo26721882021-08-11 17:42:52 -040082// Hooks: make(logrus.LevelHooks),
khenaidoo59ce9dd2019-11-11 13:05:32 -050083// Level: logrus.DebugLevel,
84// }
85//
86// It's recommended to make this a global instance called `log`.
87func 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
98func (logger *Logger) newEntry() *Entry {
99 entry, ok := logger.entryPool.Get().(*Entry)
100 if ok {
101 return entry
102 }
103 return NewEntry(logger)
104}
105
106func (logger *Logger) releaseEntry(entry *Entry) {
107 entry.Data = map[string]interface{}{}
108 logger.entryPool.Put(entry)
109}
110
khenaidoo26721882021-08-11 17:42:52 -0400111// 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.
khenaidoo59ce9dd2019-11-11 13:05:32 -0500114// If you want multiple fields, use `WithFields`.
115func (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`.
123func (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`.
131func (logger *Logger) WithError(err error) *Entry {
132 entry := logger.newEntry()
133 defer logger.releaseEntry(entry)
134 return entry.WithError(err)
135}
136
khenaidoo26721882021-08-11 17:42:52 -0400137// Add a context to the log entry.
138func (logger *Logger) WithContext(ctx context.Context) *Entry {
139 entry := logger.newEntry()
140 defer logger.releaseEntry(entry)
141 return entry.WithContext(ctx)
142}
143
khenaidoo59ce9dd2019-11-11 13:05:32 -0500144// Overrides the time of the log entry.
145func (logger *Logger) WithTime(t time.Time) *Entry {
146 entry := logger.newEntry()
147 defer logger.releaseEntry(entry)
148 return entry.WithTime(t)
149}
150
khenaidoo26721882021-08-11 17:42:52 -0400151func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
152 if logger.IsLevelEnabled(level) {
khenaidoo59ce9dd2019-11-11 13:05:32 -0500153 entry := logger.newEntry()
khenaidoo26721882021-08-11 17:42:52 -0400154 entry.Logf(level, format, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500155 logger.releaseEntry(entry)
156 }
157}
158
khenaidoo26721882021-08-11 17:42:52 -0400159func (logger *Logger) Tracef(format string, args ...interface{}) {
160 logger.Logf(TraceLevel, format, args...)
161}
162
khenaidoo59ce9dd2019-11-11 13:05:32 -0500163func (logger *Logger) Debugf(format string, args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400164 logger.Logf(DebugLevel, format, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500165}
166
167func (logger *Logger) Infof(format string, args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400168 logger.Logf(InfoLevel, format, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500169}
170
171func (logger *Logger) Printf(format string, args ...interface{}) {
172 entry := logger.newEntry()
173 entry.Printf(format, args...)
174 logger.releaseEntry(entry)
175}
176
177func (logger *Logger) Warnf(format string, args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400178 logger.Logf(WarnLevel, format, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500179}
180
181func (logger *Logger) Warningf(format string, args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400182 logger.Warnf(format, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500183}
184
185func (logger *Logger) Errorf(format string, args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400186 logger.Logf(ErrorLevel, format, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500187}
188
189func (logger *Logger) Fatalf(format string, args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400190 logger.Logf(FatalLevel, format, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500191 logger.Exit(1)
192}
193
194func (logger *Logger) Panicf(format string, args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400195 logger.Logf(PanicLevel, format, args...)
196}
197
Abhay Kumar40252eb2025-10-13 13:25:53 +0000198// 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.
khenaidoo26721882021-08-11 17:42:52 -0400201func (logger *Logger) Log(level Level, args ...interface{}) {
202 if logger.IsLevelEnabled(level) {
khenaidoo59ce9dd2019-11-11 13:05:32 -0500203 entry := logger.newEntry()
khenaidoo26721882021-08-11 17:42:52 -0400204 entry.Log(level, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500205 logger.releaseEntry(entry)
206 }
207}
208
Abhay Kumar40252eb2025-10-13 13:25:53 +0000209func (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
khenaidoo59ce9dd2019-11-11 13:05:32 -0500217func (logger *Logger) Trace(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400218 logger.Log(TraceLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500219}
220
221func (logger *Logger) Debug(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400222 logger.Log(DebugLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500223}
224
225func (logger *Logger) Info(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400226 logger.Log(InfoLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500227}
228
229func (logger *Logger) Print(args ...interface{}) {
230 entry := logger.newEntry()
khenaidoo26721882021-08-11 17:42:52 -0400231 entry.Print(args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500232 logger.releaseEntry(entry)
233}
234
235func (logger *Logger) Warn(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400236 logger.Log(WarnLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500237}
238
239func (logger *Logger) Warning(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400240 logger.Warn(args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500241}
242
243func (logger *Logger) Error(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400244 logger.Log(ErrorLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500245}
246
247func (logger *Logger) Fatal(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400248 logger.Log(FatalLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500249 logger.Exit(1)
250}
251
252func (logger *Logger) Panic(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400253 logger.Log(PanicLevel, args...)
254}
255
Abhay Kumar40252eb2025-10-13 13:25:53 +0000256func (logger *Logger) TraceFn(fn LogFunction) {
257 logger.LogFn(TraceLevel, fn)
258}
259
260func (logger *Logger) DebugFn(fn LogFunction) {
261 logger.LogFn(DebugLevel, fn)
262}
263
264func (logger *Logger) InfoFn(fn LogFunction) {
265 logger.LogFn(InfoLevel, fn)
266}
267
268func (logger *Logger) PrintFn(fn LogFunction) {
269 entry := logger.newEntry()
270 entry.Print(fn()...)
271 logger.releaseEntry(entry)
272}
273
274func (logger *Logger) WarnFn(fn LogFunction) {
275 logger.LogFn(WarnLevel, fn)
276}
277
278func (logger *Logger) WarningFn(fn LogFunction) {
279 logger.WarnFn(fn)
280}
281
282func (logger *Logger) ErrorFn(fn LogFunction) {
283 logger.LogFn(ErrorLevel, fn)
284}
285
286func (logger *Logger) FatalFn(fn LogFunction) {
287 logger.LogFn(FatalLevel, fn)
288 logger.Exit(1)
289}
290
291func (logger *Logger) PanicFn(fn LogFunction) {
292 logger.LogFn(PanicLevel, fn)
293}
294
khenaidoo26721882021-08-11 17:42:52 -0400295func (logger *Logger) Logln(level Level, args ...interface{}) {
296 if logger.IsLevelEnabled(level) {
khenaidoo59ce9dd2019-11-11 13:05:32 -0500297 entry := logger.newEntry()
khenaidoo26721882021-08-11 17:42:52 -0400298 entry.Logln(level, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500299 logger.releaseEntry(entry)
300 }
301}
302
303func (logger *Logger) Traceln(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400304 logger.Logln(TraceLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500305}
306
307func (logger *Logger) Debugln(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400308 logger.Logln(DebugLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500309}
310
311func (logger *Logger) Infoln(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400312 logger.Logln(InfoLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500313}
314
315func (logger *Logger) Println(args ...interface{}) {
316 entry := logger.newEntry()
317 entry.Println(args...)
318 logger.releaseEntry(entry)
319}
320
321func (logger *Logger) Warnln(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400322 logger.Logln(WarnLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500323}
324
325func (logger *Logger) Warningln(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400326 logger.Warnln(args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500327}
328
329func (logger *Logger) Errorln(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400330 logger.Logln(ErrorLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500331}
332
333func (logger *Logger) Fatalln(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400334 logger.Logln(FatalLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500335 logger.Exit(1)
336}
337
338func (logger *Logger) Panicln(args ...interface{}) {
khenaidoo26721882021-08-11 17:42:52 -0400339 logger.Logln(PanicLevel, args...)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500340}
341
342func (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.
353func (logger *Logger) SetNoLock() {
354 logger.mu.Disable()
355}
356
357func (logger *Logger) level() Level {
358 return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
359}
360
361// SetLevel sets the logger level.
362func (logger *Logger) SetLevel(level Level) {
363 atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
364}
365
366// GetLevel returns the logger level.
367func (logger *Logger) GetLevel() Level {
368 return logger.level()
369}
370
371// AddHook adds a hook to the logger hooks.
372func (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
379func (logger *Logger) IsLevelEnabled(level Level) bool {
380 return logger.level() >= level
381}
382
383// SetFormatter sets the logger formatter.
384func (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.
391func (logger *Logger) SetOutput(output io.Writer) {
392 logger.mu.Lock()
393 defer logger.mu.Unlock()
394 logger.Out = output
395}
396
397func (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
404func (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}
Abhay Kumar40252eb2025-10-13 13:25:53 +0000411
412// SetBufferPool sets the logger buffer pool.
413func (logger *Logger) SetBufferPool(pool BufferPool) {
414 logger.mu.Lock()
415 defer logger.mu.Unlock()
416 logger.BufferPool = pool
417}