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