1package 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} 416