github.com/apex/log@v1.9.0/entry.go (about)

     1  package log
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  	"time"
     8  )
     9  
    10  // assert interface compliance.
    11  var _ Interface = (*Entry)(nil)
    12  
    13  // Now returns the current time.
    14  var Now = time.Now
    15  
    16  // Entry represents a single log entry.
    17  type Entry struct {
    18  	Logger    *Logger   `json:"-"`
    19  	Fields    Fields    `json:"fields"`
    20  	Level     Level     `json:"level"`
    21  	Timestamp time.Time `json:"timestamp"`
    22  	Message   string    `json:"message"`
    23  	start     time.Time
    24  	fields    []Fields
    25  }
    26  
    27  // NewEntry returns a new entry for `log`.
    28  func NewEntry(log *Logger) *Entry {
    29  	return &Entry{
    30  		Logger: log,
    31  	}
    32  }
    33  
    34  // WithFields returns a new entry with `fields` set.
    35  func (e *Entry) WithFields(fields Fielder) *Entry {
    36  	f := []Fields{}
    37  	f = append(f, e.fields...)
    38  	f = append(f, fields.Fields())
    39  	return &Entry{
    40  		Logger: e.Logger,
    41  		fields: f,
    42  	}
    43  }
    44  
    45  // WithField returns a new entry with the `key` and `value` set.
    46  func (e *Entry) WithField(key string, value interface{}) *Entry {
    47  	return e.WithFields(Fields{key: value})
    48  }
    49  
    50  // WithDuration returns a new entry with the "duration" field set
    51  // to the given duration in milliseconds.
    52  func (e *Entry) WithDuration(d time.Duration) *Entry {
    53  	return e.WithField("duration", d.Milliseconds())
    54  }
    55  
    56  // WithError returns a new entry with the "error" set to `err`.
    57  //
    58  // The given error may implement .Fielder, if it does the method
    59  // will add all its `.Fields()` into the returned entry.
    60  func (e *Entry) WithError(err error) *Entry {
    61  	if err == nil {
    62  		return e
    63  	}
    64  
    65  	ctx := e.WithField("error", err.Error())
    66  
    67  	if s, ok := err.(stackTracer); ok {
    68  		frame := s.StackTrace()[0]
    69  
    70  		name := fmt.Sprintf("%n", frame)
    71  		file := fmt.Sprintf("%+s", frame)
    72  		line := fmt.Sprintf("%d", frame)
    73  
    74  		parts := strings.Split(file, "\n\t")
    75  		if len(parts) > 1 {
    76  			file = parts[1]
    77  		}
    78  
    79  		ctx = ctx.WithField("source", fmt.Sprintf("%s: %s:%s", name, file, line))
    80  	}
    81  
    82  	if f, ok := err.(Fielder); ok {
    83  		ctx = ctx.WithFields(f.Fields())
    84  	}
    85  
    86  	return ctx
    87  }
    88  
    89  // Debug level message.
    90  func (e *Entry) Debug(msg string) {
    91  	e.Logger.log(DebugLevel, e, msg)
    92  }
    93  
    94  // Info level message.
    95  func (e *Entry) Info(msg string) {
    96  	e.Logger.log(InfoLevel, e, msg)
    97  }
    98  
    99  // Warn level message.
   100  func (e *Entry) Warn(msg string) {
   101  	e.Logger.log(WarnLevel, e, msg)
   102  }
   103  
   104  // Error level message.
   105  func (e *Entry) Error(msg string) {
   106  	e.Logger.log(ErrorLevel, e, msg)
   107  }
   108  
   109  // Fatal level message, followed by an exit.
   110  func (e *Entry) Fatal(msg string) {
   111  	e.Logger.log(FatalLevel, e, msg)
   112  	os.Exit(1)
   113  }
   114  
   115  // Debugf level formatted message.
   116  func (e *Entry) Debugf(msg string, v ...interface{}) {
   117  	e.Debug(fmt.Sprintf(msg, v...))
   118  }
   119  
   120  // Infof level formatted message.
   121  func (e *Entry) Infof(msg string, v ...interface{}) {
   122  	e.Info(fmt.Sprintf(msg, v...))
   123  }
   124  
   125  // Warnf level formatted message.
   126  func (e *Entry) Warnf(msg string, v ...interface{}) {
   127  	e.Warn(fmt.Sprintf(msg, v...))
   128  }
   129  
   130  // Errorf level formatted message.
   131  func (e *Entry) Errorf(msg string, v ...interface{}) {
   132  	e.Error(fmt.Sprintf(msg, v...))
   133  }
   134  
   135  // Fatalf level formatted message, followed by an exit.
   136  func (e *Entry) Fatalf(msg string, v ...interface{}) {
   137  	e.Fatal(fmt.Sprintf(msg, v...))
   138  }
   139  
   140  // Trace returns a new entry with a Stop method to fire off
   141  // a corresponding completion log, useful with defer.
   142  func (e *Entry) Trace(msg string) *Entry {
   143  	e.Info(msg)
   144  	v := e.WithFields(e.Fields)
   145  	v.Message = msg
   146  	v.start = time.Now()
   147  	return v
   148  }
   149  
   150  // Stop should be used with Trace, to fire off the completion message. When
   151  // an `err` is passed the "error" field is set, and the log level is error.
   152  func (e *Entry) Stop(err *error) {
   153  	if err == nil || *err == nil {
   154  		e.WithDuration(time.Since(e.start)).Info(e.Message)
   155  	} else {
   156  		e.WithDuration(time.Since(e.start)).WithError(*err).Error(e.Message)
   157  	}
   158  }
   159  
   160  // mergedFields returns the fields list collapsed into a single map.
   161  func (e *Entry) mergedFields() Fields {
   162  	f := Fields{}
   163  
   164  	for _, fields := range e.fields {
   165  		for k, v := range fields {
   166  			f[k] = v
   167  		}
   168  	}
   169  
   170  	return f
   171  }
   172  
   173  // finalize returns a copy of the Entry with Fields merged.
   174  func (e *Entry) finalize(level Level, msg string) *Entry {
   175  	return &Entry{
   176  		Logger:    e.Logger,
   177  		Fields:    e.mergedFields(),
   178  		Level:     level,
   179  		Message:   msg,
   180  		Timestamp: Now(),
   181  	}
   182  }