logger.go raw

   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  }
 418