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