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 = &logrus.Logger{ 72// Out: os.Stderr, 73// Formatter: new(logrus.JSONFormatter), 74// Hooks: make(logrus.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// WithField allocates a new entry and adds a field to it. 104// Debug, Print, Info, Warn, Error, Fatal or Panic must be then applied to 105// this new returned entry. 106// If you want multiple fields, use `WithFields`. 107func (logger *Logger) WithField(key string, value interface{}) *Entry { 108 entry := logger.newEntry() 109 defer logger.releaseEntry(entry) 110 return entry.WithField(key, value) 111} 112 113// Adds a struct of fields to the log entry. All it does is call `WithField` for 114// each `Field`. 115func (logger *Logger) WithFields(fields Fields) *Entry { 116 entry := logger.newEntry() 117 defer logger.releaseEntry(entry) 118 return entry.WithFields(fields) 119} 120 121// Add an error as single field to the log entry. All it does is call 122// `WithError` for the given `error`. 123func (logger *Logger) WithError(err error) *Entry { 124 entry := logger.newEntry() 125 defer logger.releaseEntry(entry) 126 return entry.WithError(err) 127} 128 129// Add a context to the log entry. 130func (logger *Logger) WithContext(ctx context.Context) *Entry { 131 entry := logger.newEntry() 132 defer logger.releaseEntry(entry) 133 return entry.WithContext(ctx) 134} 135 136// Overrides the time of the log entry. 137func (logger *Logger) WithTime(t time.Time) *Entry { 138 entry := logger.newEntry() 139 defer logger.releaseEntry(entry) 140 return entry.WithTime(t) 141} 142 143func (logger *Logger) Logf(level Level, format string, args ...interface{}) { 144 if logger.IsLevelEnabled(level) { 145 entry := logger.newEntry() 146 entry.Logf(level, format, args...) 147 logger.releaseEntry(entry) 148 } 149} 150 151func (logger *Logger) Tracef(format string, args ...interface{}) { 152 logger.Logf(TraceLevel, format, args...) 153} 154 155func (logger *Logger) Debugf(format string, args ...interface{}) { 156 logger.Logf(DebugLevel, format, args...) 157} 158 159func (logger *Logger) Infof(format string, args ...interface{}) { 160 logger.Logf(InfoLevel, format, args...) 161} 162 163func (logger *Logger) Printf(format string, args ...interface{}) { 164 entry := logger.newEntry() 165 entry.Printf(format, args...) 166 logger.releaseEntry(entry) 167} 168 169func (logger *Logger) Warnf(format string, args ...interface{}) { 170 logger.Logf(WarnLevel, format, args...) 171} 172 173func (logger *Logger) Warningf(format string, args ...interface{}) { 174 logger.Warnf(format, args...) 175} 176 177func (logger *Logger) Errorf(format string, args ...interface{}) { 178 logger.Logf(ErrorLevel, format, args...) 179} 180 181func (logger *Logger) Fatalf(format string, args ...interface{}) { 182 logger.Logf(FatalLevel, format, args...) 183 logger.Exit(1) 184} 185 186func (logger *Logger) Panicf(format string, args ...interface{}) { 187 logger.Logf(PanicLevel, format, args...) 188} 189 190func (logger *Logger) Log(level Level, args ...interface{}) { 191 if logger.IsLevelEnabled(level) { 192 entry := logger.newEntry() 193 entry.Log(level, args...) 194 logger.releaseEntry(entry) 195 } 196} 197 198func (logger *Logger) Trace(args ...interface{}) { 199 logger.Log(TraceLevel, args...) 200} 201 202func (logger *Logger) Debug(args ...interface{}) { 203 logger.Log(DebugLevel, args...) 204} 205 206func (logger *Logger) Info(args ...interface{}) { 207 logger.Log(InfoLevel, args...) 208} 209 210func (logger *Logger) Print(args ...interface{}) { 211 entry := logger.newEntry() 212 entry.Print(args...) 213 logger.releaseEntry(entry) 214} 215 216func (logger *Logger) Warn(args ...interface{}) { 217 logger.Log(WarnLevel, args...) 218} 219 220func (logger *Logger) Warning(args ...interface{}) { 221 logger.Warn(args...) 222} 223 224func (logger *Logger) Error(args ...interface{}) { 225 logger.Log(ErrorLevel, args...) 226} 227 228func (logger *Logger) Fatal(args ...interface{}) { 229 logger.Log(FatalLevel, args...) 230 logger.Exit(1) 231} 232 233func (logger *Logger) Panic(args ...interface{}) { 234 logger.Log(PanicLevel, args...) 235} 236 237func (logger *Logger) Logln(level Level, args ...interface{}) { 238 if logger.IsLevelEnabled(level) { 239 entry := logger.newEntry() 240 entry.Logln(level, args...) 241 logger.releaseEntry(entry) 242 } 243} 244 245func (logger *Logger) Traceln(args ...interface{}) { 246 logger.Logln(TraceLevel, args...) 247} 248 249func (logger *Logger) Debugln(args ...interface{}) { 250 logger.Logln(DebugLevel, args...) 251} 252 253func (logger *Logger) Infoln(args ...interface{}) { 254 logger.Logln(InfoLevel, args...) 255} 256 257func (logger *Logger) Println(args ...interface{}) { 258 entry := logger.newEntry() 259 entry.Println(args...) 260 logger.releaseEntry(entry) 261} 262 263func (logger *Logger) Warnln(args ...interface{}) { 264 logger.Logln(WarnLevel, args...) 265} 266 267func (logger *Logger) Warningln(args ...interface{}) { 268 logger.Warnln(args...) 269} 270 271func (logger *Logger) Errorln(args ...interface{}) { 272 logger.Logln(ErrorLevel, args...) 273} 274 275func (logger *Logger) Fatalln(args ...interface{}) { 276 logger.Logln(FatalLevel, args...) 277 logger.Exit(1) 278} 279 280func (logger *Logger) Panicln(args ...interface{}) { 281 logger.Logln(PanicLevel, args...) 282} 283 284func (logger *Logger) Exit(code int) { 285 runHandlers() 286 if logger.ExitFunc == nil { 287 logger.ExitFunc = os.Exit 288 } 289 logger.ExitFunc(code) 290} 291 292//When file is opened with appending mode, it's safe to 293//write concurrently to a file (within 4k message on Linux). 294//In these cases user can choose to disable the lock. 295func (logger *Logger) SetNoLock() { 296 logger.mu.Disable() 297} 298 299func (logger *Logger) level() Level { 300 return Level(atomic.LoadUint32((*uint32)(&logger.Level))) 301} 302 303// SetLevel sets the logger level. 304func (logger *Logger) SetLevel(level Level) { 305 atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) 306} 307 308// GetLevel returns the logger level. 309func (logger *Logger) GetLevel() Level { 310 return logger.level() 311} 312 313// AddHook adds a hook to the logger hooks. 314func (logger *Logger) AddHook(hook Hook) { 315 logger.mu.Lock() 316 defer logger.mu.Unlock() 317 logger.Hooks.Add(hook) 318} 319 320// IsLevelEnabled checks if the log level of the logger is greater than the level param 321func (logger *Logger) IsLevelEnabled(level Level) bool { 322 return logger.level() >= level 323} 324 325// SetFormatter sets the logger formatter. 326func (logger *Logger) SetFormatter(formatter Formatter) { 327 logger.mu.Lock() 328 defer logger.mu.Unlock() 329 logger.Formatter = formatter 330} 331 332// SetOutput sets the logger output. 333func (logger *Logger) SetOutput(output io.Writer) { 334 logger.mu.Lock() 335 defer logger.mu.Unlock() 336 logger.Out = output 337} 338 339func (logger *Logger) SetReportCaller(reportCaller bool) { 340 logger.mu.Lock() 341 defer logger.mu.Unlock() 342 logger.ReportCaller = reportCaller 343} 344 345// ReplaceHooks replaces the logger hooks and returns the old ones 346func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks { 347 logger.mu.Lock() 348 oldHooks := logger.Hooks 349 logger.Hooks = hooks 350 logger.mu.Unlock() 351 return oldHooks 352} 353