...

Source file src/github.com/sirupsen/logrus/entry.go

Documentation: github.com/sirupsen/logrus

     1  package logrus
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"runtime"
     9  	"strings"
    10  	"sync"
    11  	"time"
    12  )
    13  
    14  var (
    15  	bufferPool *sync.Pool
    16  
    17  	// qualified package name, cached at first use
    18  	logrusPackage string
    19  
    20  	// Positions in the call stack when tracing to report the calling method
    21  	minimumCallerDepth int
    22  
    23  	// Used for caller information initialisation
    24  	callerInitOnce sync.Once
    25  )
    26  
    27  const (
    28  	maximumCallerDepth int = 25
    29  	knownLogrusFrames  int = 4
    30  )
    31  
    32  func init() {
    33  	bufferPool = &sync.Pool{
    34  		New: func() interface{} {
    35  			return new(bytes.Buffer)
    36  		},
    37  	}
    38  
    39  	// start at the bottom of the stack before the package-name cache is primed
    40  	minimumCallerDepth = 1
    41  }
    42  
    43  // Defines the key when adding errors using WithError.
    44  var ErrorKey = "error"
    45  
    46  // An entry is the final or intermediate Logrus logging entry. It contains all
    47  // the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
    48  // Info, Warn, Error, Fatal or Panic is called on it. These objects can be
    49  // reused and passed around as much as you wish to avoid field duplication.
    50  type Entry struct {
    51  	Logger *Logger
    52  
    53  	// Contains all the fields set by the user.
    54  	Data Fields
    55  
    56  	// Time at which the log entry was created
    57  	Time time.Time
    58  
    59  	// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
    60  	// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
    61  	Level Level
    62  
    63  	// Calling method, with package name
    64  	Caller *runtime.Frame
    65  
    66  	// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
    67  	Message string
    68  
    69  	// When formatter is called in entry.log(), a Buffer may be set to entry
    70  	Buffer *bytes.Buffer
    71  
    72  	// err may contain a field formatting error
    73  	err string
    74  }
    75  
    76  func NewEntry(logger *Logger) *Entry {
    77  	return &Entry{
    78  		Logger: logger,
    79  		// Default is three fields, plus one optional.  Give a little extra room.
    80  		Data: make(Fields, 6),
    81  	}
    82  }
    83  
    84  // Returns the string representation from the reader and ultimately the
    85  // formatter.
    86  func (entry *Entry) String() (string, error) {
    87  	serialized, err := entry.Logger.Formatter.Format(entry)
    88  	if err != nil {
    89  		return "", err
    90  	}
    91  	str := string(serialized)
    92  	return str, nil
    93  }
    94  
    95  // Add an error as single field (using the key defined in ErrorKey) to the Entry.
    96  func (entry *Entry) WithError(err error) *Entry {
    97  	return entry.WithField(ErrorKey, err)
    98  }
    99  
   100  // Add a single field to the Entry.
   101  func (entry *Entry) WithField(key string, value interface{}) *Entry {
   102  	return entry.WithFields(Fields{key: value})
   103  }
   104  
   105  // Add a map of fields to the Entry.
   106  func (entry *Entry) WithFields(fields Fields) *Entry {
   107  	data := make(Fields, len(entry.Data)+len(fields))
   108  	for k, v := range entry.Data {
   109  		data[k] = v
   110  	}
   111  	fieldErr := entry.err
   112  	for k, v := range fields {
   113  		isErrField := false
   114  		if t := reflect.TypeOf(v); t != nil {
   115  			switch t.Kind() {
   116  			case reflect.Func:
   117  				isErrField = true
   118  			case reflect.Ptr:
   119  				isErrField = t.Elem().Kind() == reflect.Func
   120  			}
   121  		}
   122  		if isErrField {
   123  			tmp := fmt.Sprintf("can not add field %q", k)
   124  			if fieldErr != "" {
   125  				fieldErr = entry.err + ", " + tmp
   126  			} else {
   127  				fieldErr = tmp
   128  			}
   129  		} else {
   130  			data[k] = v
   131  		}
   132  	}
   133  	return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr}
   134  }
   135  
   136  // Overrides the time of the Entry.
   137  func (entry *Entry) WithTime(t time.Time) *Entry {
   138  	return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err}
   139  }
   140  
   141  // getPackageName reduces a fully qualified function name to the package name
   142  // There really ought to be to be a better way...
   143  func getPackageName(f string) string {
   144  	for {
   145  		lastPeriod := strings.LastIndex(f, ".")
   146  		lastSlash := strings.LastIndex(f, "/")
   147  		if lastPeriod > lastSlash {
   148  			f = f[:lastPeriod]
   149  		} else {
   150  			break
   151  		}
   152  	}
   153  
   154  	return f
   155  }
   156  
   157  // getCaller retrieves the name of the first non-logrus calling function
   158  func getCaller() *runtime.Frame {
   159  	// Restrict the lookback frames to avoid runaway lookups
   160  	pcs := make([]uintptr, maximumCallerDepth)
   161  	depth := runtime.Callers(minimumCallerDepth, pcs)
   162  	frames := runtime.CallersFrames(pcs[:depth])
   163  
   164  	// cache this package's fully-qualified name
   165  	callerInitOnce.Do(func() {
   166  		logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name())
   167  
   168  		// now that we have the cache, we can skip a minimum count of known-logrus functions
   169  		// XXX this is dubious, the number of frames may vary store an entry in a logger interface
   170  		minimumCallerDepth = knownLogrusFrames
   171  	})
   172  
   173  	for f, again := frames.Next(); again; f, again = frames.Next() {
   174  		pkg := getPackageName(f.Function)
   175  
   176  		// If the caller isn't part of this package, we're done
   177  		if pkg != logrusPackage {
   178  			return &f
   179  		}
   180  	}
   181  
   182  	// if we got here, we failed to find the caller's context
   183  	return nil
   184  }
   185  
   186  func (entry Entry) HasCaller() (has bool) {
   187  	return entry.Logger != nil &&
   188  		entry.Logger.ReportCaller &&
   189  		entry.Caller != nil
   190  }
   191  
   192  // This function is not declared with a pointer value because otherwise
   193  // race conditions will occur when using multiple goroutines
   194  func (entry Entry) log(level Level, msg string) {
   195  	var buffer *bytes.Buffer
   196  
   197  	// Default to now, but allow users to override if they want.
   198  	//
   199  	// We don't have to worry about polluting future calls to Entry#log()
   200  	// with this assignment because this function is declared with a
   201  	// non-pointer receiver.
   202  	if entry.Time.IsZero() {
   203  		entry.Time = time.Now()
   204  	}
   205  
   206  	entry.Level = level
   207  	entry.Message = msg
   208  	if entry.Logger.ReportCaller {
   209  		entry.Caller = getCaller()
   210  	}
   211  
   212  	entry.fireHooks()
   213  
   214  	buffer = bufferPool.Get().(*bytes.Buffer)
   215  	buffer.Reset()
   216  	defer bufferPool.Put(buffer)
   217  	entry.Buffer = buffer
   218  
   219  	entry.write()
   220  
   221  	entry.Buffer = nil
   222  
   223  	// To avoid Entry#log() returning a value that only would make sense for
   224  	// panic() to use in Entry#Panic(), we avoid the allocation by checking
   225  	// directly here.
   226  	if level <= PanicLevel {
   227  		panic(&entry)
   228  	}
   229  }
   230  
   231  func (entry *Entry) fireHooks() {
   232  	entry.Logger.mu.Lock()
   233  	defer entry.Logger.mu.Unlock()
   234  	err := entry.Logger.Hooks.Fire(entry.Level, entry)
   235  	if err != nil {
   236  		fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
   237  	}
   238  }
   239  
   240  func (entry *Entry) write() {
   241  	entry.Logger.mu.Lock()
   242  	defer entry.Logger.mu.Unlock()
   243  	serialized, err := entry.Logger.Formatter.Format(entry)
   244  	if err != nil {
   245  		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
   246  	} else {
   247  		_, err = entry.Logger.Out.Write(serialized)
   248  		if err != nil {
   249  			fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
   250  		}
   251  	}
   252  }
   253  
   254  func (entry *Entry) Log(level Level, args ...interface{}) {
   255  	if entry.Logger.IsLevelEnabled(level) {
   256  		entry.log(level, fmt.Sprint(args...))
   257  	}
   258  }
   259  
   260  func (entry *Entry) Trace(args ...interface{}) {
   261  	entry.Log(TraceLevel, args...)
   262  }
   263  
   264  func (entry *Entry) Debug(args ...interface{}) {
   265  	entry.Log(DebugLevel, args...)
   266  }
   267  
   268  func (entry *Entry) Print(args ...interface{}) {
   269  	entry.Info(args...)
   270  }
   271  
   272  func (entry *Entry) Info(args ...interface{}) {
   273  	entry.Log(InfoLevel, args...)
   274  }
   275  
   276  func (entry *Entry) Warn(args ...interface{}) {
   277  	entry.Log(WarnLevel, args...)
   278  }
   279  
   280  func (entry *Entry) Warning(args ...interface{}) {
   281  	entry.Warn(args...)
   282  }
   283  
   284  func (entry *Entry) Error(args ...interface{}) {
   285  	entry.Log(ErrorLevel, args...)
   286  }
   287  
   288  func (entry *Entry) Fatal(args ...interface{}) {
   289  	entry.Log(FatalLevel, args...)
   290  	entry.Logger.Exit(1)
   291  }
   292  
   293  func (entry *Entry) Panic(args ...interface{}) {
   294  	entry.Log(PanicLevel, args...)
   295  	panic(fmt.Sprint(args...))
   296  }
   297  
   298  // Entry Printf family functions
   299  
   300  func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
   301  	entry.Log(level, fmt.Sprintf(format, args...))
   302  }
   303  
   304  func (entry *Entry) Tracef(format string, args ...interface{}) {
   305  	entry.Logf(TraceLevel, format, args...)
   306  }
   307  
   308  func (entry *Entry) Debugf(format string, args ...interface{}) {
   309  	entry.Logf(DebugLevel, format, args...)
   310  }
   311  
   312  func (entry *Entry) Infof(format string, args ...interface{}) {
   313  	entry.Logf(InfoLevel, format, args...)
   314  }
   315  
   316  func (entry *Entry) Printf(format string, args ...interface{}) {
   317  	entry.Infof(format, args...)
   318  }
   319  
   320  func (entry *Entry) Warnf(format string, args ...interface{}) {
   321  	entry.Logf(WarnLevel, format, args...)
   322  }
   323  
   324  func (entry *Entry) Warningf(format string, args ...interface{}) {
   325  	entry.Warnf(format, args...)
   326  }
   327  
   328  func (entry *Entry) Errorf(format string, args ...interface{}) {
   329  	entry.Logf(ErrorLevel, format, args...)
   330  }
   331  
   332  func (entry *Entry) Fatalf(format string, args ...interface{}) {
   333  	entry.Logf(FatalLevel, format, args...)
   334  	entry.Logger.Exit(1)
   335  }
   336  
   337  func (entry *Entry) Panicf(format string, args ...interface{}) {
   338  	entry.Logf(PanicLevel, format, args...)
   339  }
   340  
   341  // Entry Println family functions
   342  
   343  func (entry *Entry) Logln(level Level, args ...interface{}) {
   344  	if entry.Logger.IsLevelEnabled(level) {
   345  		entry.Log(level, entry.sprintlnn(args...))
   346  	}
   347  }
   348  
   349  func (entry *Entry) Traceln(args ...interface{}) {
   350  	entry.Logln(TraceLevel, args...)
   351  }
   352  
   353  func (entry *Entry) Debugln(args ...interface{}) {
   354  	entry.Logln(DebugLevel, args...)
   355  }
   356  
   357  func (entry *Entry) Infoln(args ...interface{}) {
   358  	entry.Logln(InfoLevel, args...)
   359  }
   360  
   361  func (entry *Entry) Println(args ...interface{}) {
   362  	entry.Infoln(args...)
   363  }
   364  
   365  func (entry *Entry) Warnln(args ...interface{}) {
   366  	entry.Logln(WarnLevel, args...)
   367  }
   368  
   369  func (entry *Entry) Warningln(args ...interface{}) {
   370  	entry.Warnln(args...)
   371  }
   372  
   373  func (entry *Entry) Errorln(args ...interface{}) {
   374  	entry.Logln(ErrorLevel, args...)
   375  }
   376  
   377  func (entry *Entry) Fatalln(args ...interface{}) {
   378  	entry.Logln(FatalLevel, args...)
   379  	entry.Logger.Exit(1)
   380  }
   381  
   382  func (entry *Entry) Panicln(args ...interface{}) {
   383  	entry.Logln(PanicLevel, args...)
   384  }
   385  
   386  // Sprintlnn => Sprint no newline. This is to get the behavior of how
   387  // fmt.Sprintln where spaces are always added between operands, regardless of
   388  // their type. Instead of vendoring the Sprintln implementation to spare a
   389  // string allocation, we do the simplest thing.
   390  func (entry *Entry) sprintlnn(args ...interface{}) string {
   391  	msg := fmt.Sprintln(args...)
   392  	return msg[:len(msg)-1]
   393  }
   394  

View as plain text