1package logrus 2 3import ( 4 "bytes" 5 "fmt" 6 "os" 7 "sync" 8 "time" 9) 10 11var bufferPool *sync.Pool 12 13func init() { 14 bufferPool = &sync.Pool{ 15 New: func() interface{} { 16 return new(bytes.Buffer) 17 }, 18 } 19} 20 21// Defines the key when adding errors using WithError. 22var ErrorKey = "error" 23 24// An entry is the final or intermediate Logrus logging entry. It contains all 25// the fields passed with WithField{,s}. It's finally logged when Debug, Info, 26// Warn, Error, Fatal or Panic is called on it. These objects can be reused and 27// passed around as much as you wish to avoid field duplication. 28type Entry struct { 29 Logger *Logger 30 31 // Contains all the fields set by the user. 32 Data Fields 33 34 // Time at which the log entry was created 35 Time time.Time 36 37 // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic 38 // This field will be set on entry firing and the value will be equal to the one in Logger struct field. 39 Level Level 40 41 // Message passed to Debug, Info, Warn, Error, Fatal or Panic 42 Message string 43 44 // When formatter is called in entry.log(), an Buffer may be set to entry 45 Buffer *bytes.Buffer 46} 47 48func NewEntry(logger *Logger) *Entry { 49 return &Entry{ 50 Logger: logger, 51 // Default is three fields, give a little extra room 52 Data: make(Fields, 5), 53 } 54} 55 56// Returns the string representation from the reader and ultimately the 57// formatter. 58func (entry *Entry) String() (string, error) { 59 serialized, err := entry.Logger.Formatter.Format(entry) 60 if err != nil { 61 return "", err 62 } 63 str := string(serialized) 64 return str, nil 65} 66 67// Add an error as single field (using the key defined in ErrorKey) to the Entry. 68func (entry *Entry) WithError(err error) *Entry { 69 return entry.WithField(ErrorKey, err) 70} 71 72// Add a single field to the Entry. 73func (entry *Entry) WithField(key string, value interface{}) *Entry { 74 return entry.WithFields(Fields{key: value}) 75} 76 77// Add a map of fields to the Entry. 78func (entry *Entry) WithFields(fields Fields) *Entry { 79 data := make(Fields, len(entry.Data)+len(fields)) 80 for k, v := range entry.Data { 81 data[k] = v 82 } 83 for k, v := range fields { 84 data[k] = v 85 } 86 return &Entry{Logger: entry.Logger, Data: data} 87} 88 89// This function is not declared with a pointer value because otherwise 90// race conditions will occur when using multiple goroutines 91func (entry Entry) log(level Level, msg string) { 92 var buffer *bytes.Buffer 93 entry.Time = time.Now() 94 entry.Level = level 95 entry.Message = msg 96 97 if err := entry.Logger.Hooks.Fire(level, &entry); err != nil { 98 entry.Logger.mu.Lock() 99 fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) 100 entry.Logger.mu.Unlock() 101 } 102 buffer = bufferPool.Get().(*bytes.Buffer) 103 buffer.Reset() 104 defer bufferPool.Put(buffer) 105 entry.Buffer = buffer 106 serialized, err := entry.Logger.Formatter.Format(&entry) 107 entry.Buffer = nil 108 if err != nil { 109 entry.Logger.mu.Lock() 110 fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) 111 entry.Logger.mu.Unlock() 112 } else { 113 entry.Logger.mu.Lock() 114 _, err = entry.Logger.Out.Write(serialized) 115 if err != nil { 116 fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) 117 } 118 entry.Logger.mu.Unlock() 119 } 120 121 // To avoid Entry#log() returning a value that only would make sense for 122 // panic() to use in Entry#Panic(), we avoid the allocation by checking 123 // directly here. 124 if level <= PanicLevel { 125 panic(&entry) 126 } 127} 128 129func (entry *Entry) Debug(args ...interface{}) { 130 if entry.Logger.level() >= DebugLevel { 131 entry.log(DebugLevel, fmt.Sprint(args...)) 132 } 133} 134 135func (entry *Entry) Print(args ...interface{}) { 136 entry.Info(args...) 137} 138 139func (entry *Entry) Info(args ...interface{}) { 140 if entry.Logger.level() >= InfoLevel { 141 entry.log(InfoLevel, fmt.Sprint(args...)) 142 } 143} 144 145func (entry *Entry) Warn(args ...interface{}) { 146 if entry.Logger.level() >= WarnLevel { 147 entry.log(WarnLevel, fmt.Sprint(args...)) 148 } 149} 150 151func (entry *Entry) Warning(args ...interface{}) { 152 entry.Warn(args...) 153} 154 155func (entry *Entry) Error(args ...interface{}) { 156 if entry.Logger.level() >= ErrorLevel { 157 entry.log(ErrorLevel, fmt.Sprint(args...)) 158 } 159} 160 161func (entry *Entry) Fatal(args ...interface{}) { 162 if entry.Logger.level() >= FatalLevel { 163 entry.log(FatalLevel, fmt.Sprint(args...)) 164 } 165 Exit(1) 166} 167 168func (entry *Entry) Panic(args ...interface{}) { 169 if entry.Logger.level() >= PanicLevel { 170 entry.log(PanicLevel, fmt.Sprint(args...)) 171 } 172 panic(fmt.Sprint(args...)) 173} 174 175// Entry Printf family functions 176 177func (entry *Entry) Debugf(format string, args ...interface{}) { 178 if entry.Logger.level() >= DebugLevel { 179 entry.Debug(fmt.Sprintf(format, args...)) 180 } 181} 182 183func (entry *Entry) Infof(format string, args ...interface{}) { 184 if entry.Logger.level() >= InfoLevel { 185 entry.Info(fmt.Sprintf(format, args...)) 186 } 187} 188 189func (entry *Entry) Printf(format string, args ...interface{}) { 190 entry.Infof(format, args...) 191} 192 193func (entry *Entry) Warnf(format string, args ...interface{}) { 194 if entry.Logger.level() >= WarnLevel { 195 entry.Warn(fmt.Sprintf(format, args...)) 196 } 197} 198 199func (entry *Entry) Warningf(format string, args ...interface{}) { 200 entry.Warnf(format, args...) 201} 202 203func (entry *Entry) Errorf(format string, args ...interface{}) { 204 if entry.Logger.level() >= ErrorLevel { 205 entry.Error(fmt.Sprintf(format, args...)) 206 } 207} 208 209func (entry *Entry) Fatalf(format string, args ...interface{}) { 210 if entry.Logger.level() >= FatalLevel { 211 entry.Fatal(fmt.Sprintf(format, args...)) 212 } 213 Exit(1) 214} 215 216func (entry *Entry) Panicf(format string, args ...interface{}) { 217 if entry.Logger.level() >= PanicLevel { 218 entry.Panic(fmt.Sprintf(format, args...)) 219 } 220} 221 222// Entry Println family functions 223 224func (entry *Entry) Debugln(args ...interface{}) { 225 if entry.Logger.level() >= DebugLevel { 226 entry.Debug(entry.sprintlnn(args...)) 227 } 228} 229 230func (entry *Entry) Infoln(args ...interface{}) { 231 if entry.Logger.level() >= InfoLevel { 232 entry.Info(entry.sprintlnn(args...)) 233 } 234} 235 236func (entry *Entry) Println(args ...interface{}) { 237 entry.Infoln(args...) 238} 239 240func (entry *Entry) Warnln(args ...interface{}) { 241 if entry.Logger.level() >= WarnLevel { 242 entry.Warn(entry.sprintlnn(args...)) 243 } 244} 245 246func (entry *Entry) Warningln(args ...interface{}) { 247 entry.Warnln(args...) 248} 249 250func (entry *Entry) Errorln(args ...interface{}) { 251 if entry.Logger.level() >= ErrorLevel { 252 entry.Error(entry.sprintlnn(args...)) 253 } 254} 255 256func (entry *Entry) Fatalln(args ...interface{}) { 257 if entry.Logger.level() >= FatalLevel { 258 entry.Fatal(entry.sprintlnn(args...)) 259 } 260 Exit(1) 261} 262 263func (entry *Entry) Panicln(args ...interface{}) { 264 if entry.Logger.level() >= PanicLevel { 265 entry.Panic(entry.sprintlnn(args...)) 266 } 267} 268 269// Sprintlnn => Sprint no newline. This is to get the behavior of how 270// fmt.Sprintln where spaces are always added between operands, regardless of 271// their type. Instead of vendoring the Sprintln implementation to spare a 272// string allocation, we do the simplest thing. 273func (entry *Entry) sprintlnn(args ...interface{}) string { 274 msg := fmt.Sprintln(args...) 275 return msg[:len(msg)-1] 276} 277