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 entry.fireHooks() 98 99 buffer = bufferPool.Get().(*bytes.Buffer) 100 buffer.Reset() 101 defer bufferPool.Put(buffer) 102 entry.Buffer = buffer 103 104 entry.write() 105 106 entry.Buffer = nil 107 108 // To avoid Entry#log() returning a value that only would make sense for 109 // panic() to use in Entry#Panic(), we avoid the allocation by checking 110 // directly here. 111 if level <= PanicLevel { 112 panic(&entry) 113 } 114} 115 116// This function is not declared with a pointer value because otherwise 117// race conditions will occur when using multiple goroutines 118func (entry Entry) fireHooks() { 119 entry.Logger.mu.Lock() 120 defer entry.Logger.mu.Unlock() 121 err := entry.Logger.Hooks.Fire(entry.Level, &entry) 122 if err != nil { 123 fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) 124 } 125} 126 127func (entry *Entry) write() { 128 serialized, err := entry.Logger.Formatter.Format(entry) 129 entry.Logger.mu.Lock() 130 defer entry.Logger.mu.Unlock() 131 if err != nil { 132 fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) 133 } else { 134 _, err = entry.Logger.Out.Write(serialized) 135 if err != nil { 136 fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) 137 } 138 } 139} 140 141func (entry *Entry) Debug(args ...interface{}) { 142 if entry.Logger.level() >= DebugLevel { 143 entry.log(DebugLevel, fmt.Sprint(args...)) 144 } 145} 146 147func (entry *Entry) Print(args ...interface{}) { 148 entry.Info(args...) 149} 150 151func (entry *Entry) Info(args ...interface{}) { 152 if entry.Logger.level() >= InfoLevel { 153 entry.log(InfoLevel, fmt.Sprint(args...)) 154 } 155} 156 157func (entry *Entry) Warn(args ...interface{}) { 158 if entry.Logger.level() >= WarnLevel { 159 entry.log(WarnLevel, fmt.Sprint(args...)) 160 } 161} 162 163func (entry *Entry) Warning(args ...interface{}) { 164 entry.Warn(args...) 165} 166 167func (entry *Entry) Error(args ...interface{}) { 168 if entry.Logger.level() >= ErrorLevel { 169 entry.log(ErrorLevel, fmt.Sprint(args...)) 170 } 171} 172 173func (entry *Entry) Fatal(args ...interface{}) { 174 if entry.Logger.level() >= FatalLevel { 175 entry.log(FatalLevel, fmt.Sprint(args...)) 176 } 177 Exit(1) 178} 179 180func (entry *Entry) Panic(args ...interface{}) { 181 if entry.Logger.level() >= PanicLevel { 182 entry.log(PanicLevel, fmt.Sprint(args...)) 183 } 184 panic(fmt.Sprint(args...)) 185} 186 187// Entry Printf family functions 188 189func (entry *Entry) Debugf(format string, args ...interface{}) { 190 if entry.Logger.level() >= DebugLevel { 191 entry.Debug(fmt.Sprintf(format, args...)) 192 } 193} 194 195func (entry *Entry) Infof(format string, args ...interface{}) { 196 if entry.Logger.level() >= InfoLevel { 197 entry.Info(fmt.Sprintf(format, args...)) 198 } 199} 200 201func (entry *Entry) Printf(format string, args ...interface{}) { 202 entry.Infof(format, args...) 203} 204 205func (entry *Entry) Warnf(format string, args ...interface{}) { 206 if entry.Logger.level() >= WarnLevel { 207 entry.Warn(fmt.Sprintf(format, args...)) 208 } 209} 210 211func (entry *Entry) Warningf(format string, args ...interface{}) { 212 entry.Warnf(format, args...) 213} 214 215func (entry *Entry) Errorf(format string, args ...interface{}) { 216 if entry.Logger.level() >= ErrorLevel { 217 entry.Error(fmt.Sprintf(format, args...)) 218 } 219} 220 221func (entry *Entry) Fatalf(format string, args ...interface{}) { 222 if entry.Logger.level() >= FatalLevel { 223 entry.Fatal(fmt.Sprintf(format, args...)) 224 } 225 Exit(1) 226} 227 228func (entry *Entry) Panicf(format string, args ...interface{}) { 229 if entry.Logger.level() >= PanicLevel { 230 entry.Panic(fmt.Sprintf(format, args...)) 231 } 232} 233 234// Entry Println family functions 235 236func (entry *Entry) Debugln(args ...interface{}) { 237 if entry.Logger.level() >= DebugLevel { 238 entry.Debug(entry.sprintlnn(args...)) 239 } 240} 241 242func (entry *Entry) Infoln(args ...interface{}) { 243 if entry.Logger.level() >= InfoLevel { 244 entry.Info(entry.sprintlnn(args...)) 245 } 246} 247 248func (entry *Entry) Println(args ...interface{}) { 249 entry.Infoln(args...) 250} 251 252func (entry *Entry) Warnln(args ...interface{}) { 253 if entry.Logger.level() >= WarnLevel { 254 entry.Warn(entry.sprintlnn(args...)) 255 } 256} 257 258func (entry *Entry) Warningln(args ...interface{}) { 259 entry.Warnln(args...) 260} 261 262func (entry *Entry) Errorln(args ...interface{}) { 263 if entry.Logger.level() >= ErrorLevel { 264 entry.Error(entry.sprintlnn(args...)) 265 } 266} 267 268func (entry *Entry) Fatalln(args ...interface{}) { 269 if entry.Logger.level() >= FatalLevel { 270 entry.Fatal(entry.sprintlnn(args...)) 271 } 272 Exit(1) 273} 274 275func (entry *Entry) Panicln(args ...interface{}) { 276 if entry.Logger.level() >= PanicLevel { 277 entry.Panic(entry.sprintlnn(args...)) 278 } 279} 280 281// Sprintlnn => Sprint no newline. This is to get the behavior of how 282// fmt.Sprintln where spaces are always added between operands, regardless of 283// their type. Instead of vendoring the Sprintln implementation to spare a 284// string allocation, we do the simplest thing. 285func (entry *Entry) sprintlnn(args ...interface{}) string { 286 msg := fmt.Sprintln(args...) 287 return msg[:len(msg)-1] 288} 289