...

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

Documentation: github.com/sirupsen/logrus

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

View as plain text