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 }