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