1package logrus 2 3import ( 4 "context" 5 "io" 6 "os" 7 "sync" 8 "sync/atomic" 9 "time" 10) 11 12type Logger struct { 13 // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a 14 // file, or leave it default which is `os.Stderr`. You can also set this to 15 // something more adventurous, such as logging to Kafka. 16 Out io.Writer 17 // Hooks for the logger instance. These allow firing events based on logging 18 // levels and log entries. For example, to send errors to an error tracking 19 // service, log to StatsD or dump the core on fatal errors. 20 Hooks LevelHooks 21 // All log entries pass through the formatter before logged to Out. The 22 // included formatters are `TextFormatter` and `JSONFormatter` for which 23 // TextFormatter is the default. In development (when a TTY is attached) it 24 // logs with colors, but to a file it wouldn't. You can easily implement your 25 // own that implements the `Formatter` interface, see the `README` or included 26 // formatters for examples. 27 Formatter Formatter 28 29 // Flag for whether to log caller info (off by default) 30 ReportCaller bool 31 32 // The logging level the logger should log at. This is typically (and defaults 33 // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be 34 // logged. 35 Level Level 36 // Used to sync writing to the log. Locking is enabled by Default 37 mu MutexWrap 38 // Reusable empty entry 39 entryPool sync.Pool 40 // Function to exit the application, defaults to `os.Exit()` 41 ExitFunc exitFunc 42} 43 44type exitFunc func(int) 45 46type MutexWrap struct { 47 lock sync.Mutex 48 disabled bool 49} 50 51func (mw *MutexWrap) Lock() { 52 if !mw.disabled { 53 mw.lock.Lock() 54 } 55} 56 57func (mw *MutexWrap) Unlock() { 58 if !mw.disabled { 59 mw.lock.Unlock() 60 } 61} 62 63func (mw *MutexWrap) Disable() { 64 mw.disabled = true 65} 66 67// Creates a new logger. Configuration should be set by changing `Formatter`, 68// `Out` and `Hooks` directly on the default logger instance. You can also just 69// instantiate your own: 70// 71// var log = &Logger{ 72// Out: os.Stderr, 73// Formatter: new(JSONFormatter), 74// Hooks: make(LevelHooks), 75// Level: logrus.DebugLevel, 76// } 77// 78// It's recommended to make this a global instance called `log`. 79func New() *Logger { 80 return &Logger{ 81 Out: os.Stderr, 82 Formatter: new(TextFormatter), 83 Hooks: make(LevelHooks), 84 Level: InfoLevel, 85 ExitFunc: os.Exit, 86 ReportCaller: false, 87 } 88} 89 90func (logger *Logger) newEntry() *Entry { 91 entry, ok := logger.entryPool.Get().(*Entry) 92 if ok { 93 return entry 94 } 95 return NewEntry(logger) 96} 97 98func (logger *Logger) releaseEntry(entry *Entry) { 99 entry.Data = map[string]interface{}{} 100 logger.entryPool.Put(entry) 101} 102 103// Adds a field to the log entry, note that it doesn't log until you call 104// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry. 105// If you want multiple fields, use `WithFields`. 106func (logger *Logger) WithField(key string, value interface{}) *Entry { 107 entry := logger.newEntry() 108 defer logger.releaseEntry(entry) 109 return entry.WithField(key, value) 110} 111 112// Adds a struct of fields to the log entry. All it does is call `WithField` for 113// each `Field`. 114func (logger *Logger) WithFields(fields Fields) *Entry { 115 entry := logger.newEntry() 116 defer logger.releaseEntry(entry) 117 return entry.WithFields(fields) 118} 119 120// Add an error as single field to the log entry. All it does is call 121// `WithError` for the given `error`. 122func (logger *Logger) WithError(err error) *Entry { 123 entry := logger.newEntry() 124 defer logger.releaseEntry(entry) 125 return entry.WithError(err) 126} 127 128// Add a context to the log entry. 129func (logger *Logger) WithContext(ctx context.Context) *Entry { 130 entry := logger.newEntry() 131 defer logger.releaseEntry(entry) 132 return entry.WithContext(ctx) 133} 134 135// Overrides the time of the log entry. 136func (logger *Logger) WithTime(t time.Time) *Entry { 137 entry := logger.newEntry() 138 defer logger.releaseEntry(entry) 139 return entry.WithTime(t) 140} 141 142func (logger *Logger) Logf(level Level, format string, args ...interface{}) { 143 if logger.IsLevelEnabled(level) { 144 entry := logger.newEntry() 145 entry.Logf(level, format, args...) 146 logger.releaseEntry(entry) 147 } 148} 149 150func (logger *Logger) Tracef(format string, args ...interface{}) { 151 logger.Logf(TraceLevel, format, args...) 152} 153 154func (logger *Logger) Debugf(format string, args ...interface{}) { 155 logger.Logf(DebugLevel, format, args...) 156} 157 158func (logger *Logger) Infof(format string, args ...interface{}) { 159 logger.Logf(InfoLevel, format, args...) 160} 161 162func (logger *Logger) Printf(format string, args ...interface{}) { 163 entry := logger.newEntry() 164 entry.Printf(format, args...) 165 logger.releaseEntry(entry) 166} 167 168func (logger *Logger) Warnf(format string, args ...interface{}) { 169 logger.Logf(WarnLevel, format, args...) 170} 171 172func (logger *Logger) Warningf(format string, args ...interface{}) { 173 logger.Warnf(format, args...) 174} 175 176func (logger *Logger) Errorf(format string, args ...interface{}) { 177 logger.Logf(ErrorLevel, format, args...) 178} 179 180func (logger *Logger) Fatalf(format string, args ...interface{}) { 181 logger.Logf(FatalLevel, format, args...) 182 logger.Exit(1) 183} 184 185func (logger *Logger) Panicf(format string, args ...interface{}) { 186 logger.Logf(PanicLevel, format, args...) 187} 188 189func (logger *Logger) Log(level Level, args ...interface{}) { 190 if logger.IsLevelEnabled(level) { 191 entry := logger.newEntry() 192 entry.Log(level, args...) 193 logger.releaseEntry(entry) 194 } 195} 196 197func (logger *Logger) Trace(args ...interface{}) { 198 logger.Log(TraceLevel, args...) 199} 200 201func (logger *Logger) Debug(args ...interface{}) { 202 logger.Log(DebugLevel, args...) 203} 204 205func (logger *Logger) Info(args ...interface{}) { 206 logger.Log(InfoLevel, args...) 207} 208 209func (logger *Logger) Print(args ...interface{}) { 210 entry := logger.newEntry() 211 entry.Print(args...) 212 logger.releaseEntry(entry) 213} 214 215func (logger *Logger) Warn(args ...interface{}) { 216 logger.Log(WarnLevel, args...) 217} 218 219func (logger *Logger) Warning(args ...interface{}) { 220 logger.Warn(args...) 221} 222 223func (logger *Logger) Error(args ...interface{}) { 224 logger.Log(ErrorLevel, args...) 225} 226 227func (logger *Logger) Fatal(args ...interface{}) { 228 logger.Log(FatalLevel, args...) 229 logger.Exit(1) 230} 231 232func (logger *Logger) Panic(args ...interface{}) { 233 logger.Log(PanicLevel, args...) 234} 235 236func (logger *Logger) Logln(level Level, args ...interface{}) { 237 if logger.IsLevelEnabled(level) { 238 entry := logger.newEntry() 239 entry.Logln(level, args...) 240 logger.releaseEntry(entry) 241 } 242} 243 244func (logger *Logger) Traceln(args ...interface{}) { 245 logger.Logln(TraceLevel, args...) 246} 247 248func (logger *Logger) Debugln(args ...interface{}) { 249 logger.Logln(DebugLevel, args...) 250} 251 252func (logger *Logger) Infoln(args ...interface{}) { 253 logger.Logln(InfoLevel, args...) 254} 255 256func (logger *Logger) Println(args ...interface{}) { 257 entry := logger.newEntry() 258 entry.Println(args...) 259 logger.releaseEntry(entry) 260} 261 262func (logger *Logger) Warnln(args ...interface{}) { 263 logger.Logln(WarnLevel, args...) 264} 265 266func (logger *Logger) Warningln(args ...interface{}) { 267 logger.Warnln(args...) 268} 269 270func (logger *Logger) Errorln(args ...interface{}) { 271 logger.Logln(ErrorLevel, args...) 272} 273 274func (logger *Logger) Fatalln(args ...interface{}) { 275 logger.Logln(FatalLevel, args...) 276 logger.Exit(1) 277} 278 279func (logger *Logger) Panicln(args ...interface{}) { 280 logger.Logln(PanicLevel, args...) 281} 282 283func (logger *Logger) Exit(code int) { 284 runHandlers() 285 if logger.ExitFunc == nil { 286 logger.ExitFunc = os.Exit 287 } 288 logger.ExitFunc(code) 289} 290 291//When file is opened with appending mode, it's safe to 292//write concurrently to a file (within 4k message on Linux). 293//In these cases user can choose to disable the lock. 294func (logger *Logger) SetNoLock() { 295 logger.mu.Disable() 296} 297 298func (logger *Logger) level() Level { 299 return Level(atomic.LoadUint32((*uint32)(&logger.Level))) 300} 301 302// SetLevel sets the logger level. 303func (logger *Logger) SetLevel(level Level) { 304 atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) 305} 306 307// GetLevel returns the logger level. 308func (logger *Logger) GetLevel() Level { 309 return logger.level() 310} 311 312// AddHook adds a hook to the logger hooks. 313func (logger *Logger) AddHook(hook Hook) { 314 logger.mu.Lock() 315 defer logger.mu.Unlock() 316 logger.Hooks.Add(hook) 317} 318 319// IsLevelEnabled checks if the log level of the logger is greater than the level param 320func (logger *Logger) IsLevelEnabled(level Level) bool { 321 return logger.level() >= level 322} 323 324// SetFormatter sets the logger formatter. 325func (logger *Logger) SetFormatter(formatter Formatter) { 326 logger.mu.Lock() 327 defer logger.mu.Unlock() 328 logger.Formatter = formatter 329} 330 331// SetOutput sets the logger output. 332func (logger *Logger) SetOutput(output io.Writer) { 333 logger.mu.Lock() 334 defer logger.mu.Unlock() 335 logger.Out = output 336} 337 338func (logger *Logger) SetReportCaller(reportCaller bool) { 339 logger.mu.Lock() 340 defer logger.mu.Unlock() 341 logger.ReportCaller = reportCaller 342} 343 344// ReplaceHooks replaces the logger hooks and returns the old ones 345func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks { 346 logger.mu.Lock() 347 oldHooks := logger.Hooks 348 logger.Hooks = hooks 349 logger.mu.Unlock() 350 return oldHooks 351} 352