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