logger.go (10822B)
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 }