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