123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- package logrus
- import (
- "context"
- "io"
- "os"
- "sync"
- "sync/atomic"
- "time"
- )
- // LogFunction For big messages, it can be more efficient to pass a function
- // and only call it if the log level is actually enables rather than
- // generating the log message and then checking if the level is enabled
- type LogFunction func() []interface{}
- type Logger struct {
- // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
- // file, or leave it default which is `os.Stderr`. You can also set this to
- // something more adventurous, such as logging to Kafka.
- Out io.Writer
- // Hooks for the logger instance. These allow firing events based on logging
- // levels and log entries. For example, to send errors to an error tracking
- // service, log to StatsD or dump the core on fatal errors.
- Hooks LevelHooks
- // All log entries pass through the formatter before logged to Out. The
- // included formatters are `TextFormatter` and `JSONFormatter` for which
- // TextFormatter is the default. In development (when a TTY is attached) it
- // logs with colors, but to a file it wouldn't. You can easily implement your
- // own that implements the `Formatter` interface, see the `README` or included
- // formatters for examples.
- Formatter Formatter
- // Flag for whether to log caller info (off by default)
- ReportCaller bool
- // The logging level the logger should log at. This is typically (and defaults
- // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
- // logged.
- Level Level
- // Used to sync writing to the log. Locking is enabled by Default
- mu MutexWrap
- // Reusable empty entry
- entryPool sync.Pool
- // Function to exit the application, defaults to `os.Exit()`
- ExitFunc exitFunc
- }
- type exitFunc func(int)
- type MutexWrap struct {
- lock sync.Mutex
- disabled bool
- }
- func (mw *MutexWrap) Lock() {
- if !mw.disabled {
- mw.lock.Lock()
- }
- }
- func (mw *MutexWrap) Unlock() {
- if !mw.disabled {
- mw.lock.Unlock()
- }
- }
- func (mw *MutexWrap) Disable() {
- mw.disabled = true
- }
- // Creates a new logger. Configuration should be set by changing `Formatter`,
- // `Out` and `Hooks` directly on the default logger instance. You can also just
- // instantiate your own:
- //
- // var log = &logrus.Logger{
- // Out: os.Stderr,
- // Formatter: new(logrus.TextFormatter),
- // Hooks: make(logrus.LevelHooks),
- // Level: logrus.DebugLevel,
- // }
- //
- // It's recommended to make this a global instance called `log`.
- func New() *Logger {
- return &Logger{
- Out: os.Stderr,
- Formatter: new(TextFormatter),
- Hooks: make(LevelHooks),
- Level: InfoLevel,
- ExitFunc: os.Exit,
- ReportCaller: false,
- }
- }
- func (logger *Logger) newEntry() *Entry {
- entry, ok := logger.entryPool.Get().(*Entry)
- if ok {
- return entry
- }
- return NewEntry(logger)
- }
- func (logger *Logger) releaseEntry(entry *Entry) {
- entry.Data = map[string]interface{}{}
- logger.entryPool.Put(entry)
- }
- // WithField allocates a new entry and adds a field to it.
- // Debug, Print, Info, Warn, Error, Fatal or Panic must be then applied to
- // this new returned entry.
- // If you want multiple fields, use `WithFields`.
- func (logger *Logger) WithField(key string, value interface{}) *Entry {
- entry := logger.newEntry()
- defer logger.releaseEntry(entry)
- return entry.WithField(key, value)
- }
- // Adds a struct of fields to the log entry. All it does is call `WithField` for
- // each `Field`.
- func (logger *Logger) WithFields(fields Fields) *Entry {
- entry := logger.newEntry()
- defer logger.releaseEntry(entry)
- return entry.WithFields(fields)
- }
- // Add an error as single field to the log entry. All it does is call
- // `WithError` for the given `error`.
- func (logger *Logger) WithError(err error) *Entry {
- entry := logger.newEntry()
- defer logger.releaseEntry(entry)
- return entry.WithError(err)
- }
- // Add a context to the log entry.
- func (logger *Logger) WithContext(ctx context.Context) *Entry {
- entry := logger.newEntry()
- defer logger.releaseEntry(entry)
- return entry.WithContext(ctx)
- }
- // Overrides the time of the log entry.
- func (logger *Logger) WithTime(t time.Time) *Entry {
- entry := logger.newEntry()
- defer logger.releaseEntry(entry)
- return entry.WithTime(t)
- }
- func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
- if logger.IsLevelEnabled(level) {
- entry := logger.newEntry()
- entry.Logf(level, format, args...)
- logger.releaseEntry(entry)
- }
- }
- func (logger *Logger) Tracef(format string, args ...interface{}) {
- logger.Logf(TraceLevel, format, args...)
- }
- func (logger *Logger) Debugf(format string, args ...interface{}) {
- logger.Logf(DebugLevel, format, args...)
- }
- func (logger *Logger) Infof(format string, args ...interface{}) {
- logger.Logf(InfoLevel, format, args...)
- }
- func (logger *Logger) Printf(format string, args ...interface{}) {
- entry := logger.newEntry()
- entry.Printf(format, args...)
- logger.releaseEntry(entry)
- }
- func (logger *Logger) Warnf(format string, args ...interface{}) {
- logger.Logf(WarnLevel, format, args...)
- }
- func (logger *Logger) Warningf(format string, args ...interface{}) {
- logger.Warnf(format, args...)
- }
- func (logger *Logger) Errorf(format string, args ...interface{}) {
- logger.Logf(ErrorLevel, format, args...)
- }
- func (logger *Logger) Fatalf(format string, args ...interface{}) {
- logger.Logf(FatalLevel, format, args...)
- logger.Exit(1)
- }
- func (logger *Logger) Panicf(format string, args ...interface{}) {
- logger.Logf(PanicLevel, format, args...)
- }
- func (logger *Logger) Log(level Level, args ...interface{}) {
- if logger.IsLevelEnabled(level) {
- entry := logger.newEntry()
- entry.Log(level, args...)
- logger.releaseEntry(entry)
- }
- }
- func (logger *Logger) LogFn(level Level, fn LogFunction) {
- if logger.IsLevelEnabled(level) {
- entry := logger.newEntry()
- entry.Log(level, fn()...)
- logger.releaseEntry(entry)
- }
- }
- func (logger *Logger) Trace(args ...interface{}) {
- logger.Log(TraceLevel, args...)
- }
- func (logger *Logger) Debug(args ...interface{}) {
- logger.Log(DebugLevel, args...)
- }
- func (logger *Logger) Info(args ...interface{}) {
- logger.Log(InfoLevel, args...)
- }
- func (logger *Logger) Print(args ...interface{}) {
- entry := logger.newEntry()
- entry.Print(args...)
- logger.releaseEntry(entry)
- }
- func (logger *Logger) Warn(args ...interface{}) {
- logger.Log(WarnLevel, args...)
- }
- func (logger *Logger) Warning(args ...interface{}) {
- logger.Warn(args...)
- }
- func (logger *Logger) Error(args ...interface{}) {
- logger.Log(ErrorLevel, args...)
- }
- func (logger *Logger) Fatal(args ...interface{}) {
- logger.Log(FatalLevel, args...)
- logger.Exit(1)
- }
- func (logger *Logger) Panic(args ...interface{}) {
- logger.Log(PanicLevel, args...)
- }
- func (logger *Logger) TraceFn(fn LogFunction) {
- logger.LogFn(TraceLevel, fn)
- }
- func (logger *Logger) DebugFn(fn LogFunction) {
- logger.LogFn(DebugLevel, fn)
- }
- func (logger *Logger) InfoFn(fn LogFunction) {
- logger.LogFn(InfoLevel, fn)
- }
- func (logger *Logger) PrintFn(fn LogFunction) {
- entry := logger.newEntry()
- entry.Print(fn()...)
- logger.releaseEntry(entry)
- }
- func (logger *Logger) WarnFn(fn LogFunction) {
- logger.LogFn(WarnLevel, fn)
- }
- func (logger *Logger) WarningFn(fn LogFunction) {
- logger.WarnFn(fn)
- }
- func (logger *Logger) ErrorFn(fn LogFunction) {
- logger.LogFn(ErrorLevel, fn)
- }
- func (logger *Logger) FatalFn(fn LogFunction) {
- logger.LogFn(FatalLevel, fn)
- logger.Exit(1)
- }
- func (logger *Logger) PanicFn(fn LogFunction) {
- logger.LogFn(PanicLevel, fn)
- }
- func (logger *Logger) Logln(level Level, args ...interface{}) {
- if logger.IsLevelEnabled(level) {
- entry := logger.newEntry()
- entry.Logln(level, args...)
- logger.releaseEntry(entry)
- }
- }
- func (logger *Logger) Traceln(args ...interface{}) {
- logger.Logln(TraceLevel, args...)
- }
- func (logger *Logger) Debugln(args ...interface{}) {
- logger.Logln(DebugLevel, args...)
- }
- func (logger *Logger) Infoln(args ...interface{}) {
- logger.Logln(InfoLevel, args...)
- }
- func (logger *Logger) Println(args ...interface{}) {
- entry := logger.newEntry()
- entry.Println(args...)
- logger.releaseEntry(entry)
- }
- func (logger *Logger) Warnln(args ...interface{}) {
- logger.Logln(WarnLevel, args...)
- }
- func (logger *Logger) Warningln(args ...interface{}) {
- logger.Warnln(args...)
- }
- func (logger *Logger) Errorln(args ...interface{}) {
- logger.Logln(ErrorLevel, args...)
- }
- func (logger *Logger) Fatalln(args ...interface{}) {
- logger.Logln(FatalLevel, args...)
- logger.Exit(1)
- }
- func (logger *Logger) Panicln(args ...interface{}) {
- logger.Logln(PanicLevel, args...)
- }
- func (logger *Logger) Exit(code int) {
- runHandlers()
- if logger.ExitFunc == nil {
- logger.ExitFunc = os.Exit
- }
- logger.ExitFunc(code)
- }
- //When file is opened with appending mode, it's safe to
- //write concurrently to a file (within 4k message on Linux).
- //In these cases user can choose to disable the lock.
- func (logger *Logger) SetNoLock() {
- logger.mu.Disable()
- }
- func (logger *Logger) level() Level {
- return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
- }
- // SetLevel sets the logger level.
- func (logger *Logger) SetLevel(level Level) {
- atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
- }
- // GetLevel returns the logger level.
- func (logger *Logger) GetLevel() Level {
- return logger.level()
- }
- // AddHook adds a hook to the logger hooks.
- func (logger *Logger) AddHook(hook Hook) {
- logger.mu.Lock()
- defer logger.mu.Unlock()
- logger.Hooks.Add(hook)
- }
- // IsLevelEnabled checks if the log level of the logger is greater than the level param
- func (logger *Logger) IsLevelEnabled(level Level) bool {
- return logger.level() >= level
- }
- // SetFormatter sets the logger formatter.
- func (logger *Logger) SetFormatter(formatter Formatter) {
- logger.mu.Lock()
- defer logger.mu.Unlock()
- logger.Formatter = formatter
- }
- // SetOutput sets the logger output.
- func (logger *Logger) SetOutput(output io.Writer) {
- logger.mu.Lock()
- defer logger.mu.Unlock()
- logger.Out = output
- }
- func (logger *Logger) SetReportCaller(reportCaller bool) {
- logger.mu.Lock()
- defer logger.mu.Unlock()
- logger.ReportCaller = reportCaller
- }
- // ReplaceHooks replaces the logger hooks and returns the old ones
- func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
- logger.mu.Lock()
- oldHooks := logger.Hooks
- logger.Hooks = hooks
- logger.mu.Unlock()
- return oldHooks
- }
|