1package logrus 2 3import ( 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 15type LogFunction func() []interface{} 16 17type 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// 76// var log = &logrus.Logger{ 77// Out: os.Stderr, 78// Formatter: new(logrus.TextFormatter), 79// Hooks: make(logrus.LevelHooks), 80// 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 108// 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. 111// 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 203func (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 211func (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 250func (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 289func (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} 405