1package logrus
2
3import (
4	"io"
5	"os"
6	"sync"
7)
8
9type Logger struct {
10	// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
11	// file, or leave it default which is `os.Stderr`. You can also set this to
12	// something more adventorous, such as logging to Kafka.
13	Out io.Writer
14	// Hooks for the logger instance. These allow firing events based on logging
15	// levels and log entries. For example, to send errors to an error tracking
16	// service, log to StatsD or dump the core on fatal errors.
17	Hooks LevelHooks
18	// All log entries pass through the formatter before logged to Out. The
19	// included formatters are `TextFormatter` and `JSONFormatter` for which
20	// TextFormatter is the default. In development (when a TTY is attached) it
21	// logs with colors, but to a file it wouldn't. You can easily implement your
22	// own that implements the `Formatter` interface, see the `README` or included
23	// formatters for examples.
24	Formatter Formatter
25	// The logging level the logger should log at. This is typically (and defaults
26	// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
27	// logged. `logrus.Debug` is useful in
28	Level Level
29	// Used to sync writing to the log. Locking is enabled by Default
30	mu MutexWrap
31	// Reusable empty entry
32	entryPool sync.Pool
33}
34
35type MutexWrap struct {
36	lock     sync.Mutex
37	disabled bool
38}
39
40func (mw *MutexWrap) Lock() {
41	if !mw.disabled {
42		mw.lock.Lock()
43	}
44}
45
46func (mw *MutexWrap) Unlock() {
47	if !mw.disabled {
48		mw.lock.Unlock()
49	}
50}
51
52func (mw *MutexWrap) Disable() {
53	mw.disabled = true
54}
55
56// Creates a new logger. Configuration should be set by changing `Formatter`,
57// `Out` and `Hooks` directly on the default logger instance. You can also just
58// instantiate your own:
59//
60//    var log = &Logger{
61//      Out: os.Stderr,
62//      Formatter: new(JSONFormatter),
63//      Hooks: make(LevelHooks),
64//      Level: logrus.DebugLevel,
65//    }
66//
67// It's recommended to make this a global instance called `log`.
68func New() *Logger {
69	return &Logger{
70		Out:       os.Stderr,
71		Formatter: new(TextFormatter),
72		Hooks:     make(LevelHooks),
73		Level:     InfoLevel,
74	}
75}
76
77func (logger *Logger) newEntry() *Entry {
78	entry, ok := logger.entryPool.Get().(*Entry)
79	if ok {
80		return entry
81	}
82	return NewEntry(logger)
83}
84
85func (logger *Logger) releaseEntry(entry *Entry) {
86	logger.entryPool.Put(entry)
87}
88
89// Adds a field to the log entry, note that it doesn't log until you call
90// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
91// If you want multiple fields, use `WithFields`.
92func (logger *Logger) WithField(key string, value interface{}) *Entry {
93	entry := logger.newEntry()
94	defer logger.releaseEntry(entry)
95	return entry.WithField(key, value)
96}
97
98// Adds a struct of fields to the log entry. All it does is call `WithField` for
99// each `Field`.
100func (logger *Logger) WithFields(fields Fields) *Entry {
101	entry := logger.newEntry()
102	defer logger.releaseEntry(entry)
103	return entry.WithFields(fields)
104}
105
106// Add an error as single field to the log entry.  All it does is call
107// `WithError` for the given `error`.
108func (logger *Logger) WithError(err error) *Entry {
109	entry := logger.newEntry()
110	defer logger.releaseEntry(entry)
111	return entry.WithError(err)
112}
113
114func (logger *Logger) Debugf(format string, args ...interface{}) {
115	if logger.Level >= DebugLevel {
116		entry := logger.newEntry()
117		entry.Debugf(format, args...)
118		logger.releaseEntry(entry)
119	}
120}
121
122func (logger *Logger) Infof(format string, args ...interface{}) {
123	if logger.Level >= InfoLevel {
124		entry := logger.newEntry()
125		entry.Infof(format, args...)
126		logger.releaseEntry(entry)
127	}
128}
129
130func (logger *Logger) Printf(format string, args ...interface{}) {
131	entry := logger.newEntry()
132	entry.Printf(format, args...)
133	logger.releaseEntry(entry)
134}
135
136func (logger *Logger) Warnf(format string, args ...interface{}) {
137	if logger.Level >= WarnLevel {
138		entry := logger.newEntry()
139		entry.Warnf(format, args...)
140		logger.releaseEntry(entry)
141	}
142}
143
144func (logger *Logger) Warningf(format string, args ...interface{}) {
145	if logger.Level >= WarnLevel {
146		entry := logger.newEntry()
147		entry.Warnf(format, args...)
148		logger.releaseEntry(entry)
149	}
150}
151
152func (logger *Logger) Errorf(format string, args ...interface{}) {
153	if logger.Level >= ErrorLevel {
154		entry := logger.newEntry()
155		entry.Errorf(format, args...)
156		logger.releaseEntry(entry)
157	}
158}
159
160func (logger *Logger) Fatalf(format string, args ...interface{}) {
161	if logger.Level >= FatalLevel {
162		entry := logger.newEntry()
163		entry.Fatalf(format, args...)
164		logger.releaseEntry(entry)
165	}
166	Exit(1)
167}
168
169func (logger *Logger) Panicf(format string, args ...interface{}) {
170	if logger.Level >= PanicLevel {
171		entry := logger.newEntry()
172		entry.Panicf(format, args...)
173		logger.releaseEntry(entry)
174	}
175}
176
177func (logger *Logger) Debug(args ...interface{}) {
178	if logger.Level >= DebugLevel {
179		entry := logger.newEntry()
180		entry.Debug(args...)
181		logger.releaseEntry(entry)
182	}
183}
184
185func (logger *Logger) Info(args ...interface{}) {
186	if logger.Level >= InfoLevel {
187		entry := logger.newEntry()
188		entry.Info(args...)
189		logger.releaseEntry(entry)
190	}
191}
192
193func (logger *Logger) Print(args ...interface{}) {
194	entry := logger.newEntry()
195	entry.Info(args...)
196	logger.releaseEntry(entry)
197}
198
199func (logger *Logger) Warn(args ...interface{}) {
200	if logger.Level >= WarnLevel {
201		entry := logger.newEntry()
202		entry.Warn(args...)
203		logger.releaseEntry(entry)
204	}
205}
206
207func (logger *Logger) Warning(args ...interface{}) {
208	if logger.Level >= WarnLevel {
209		entry := logger.newEntry()
210		entry.Warn(args...)
211		logger.releaseEntry(entry)
212	}
213}
214
215func (logger *Logger) Error(args ...interface{}) {
216	if logger.Level >= ErrorLevel {
217		entry := logger.newEntry()
218		entry.Error(args...)
219		logger.releaseEntry(entry)
220	}
221}
222
223func (logger *Logger) Fatal(args ...interface{}) {
224	if logger.Level >= FatalLevel {
225		entry := logger.newEntry()
226		entry.Fatal(args...)
227		logger.releaseEntry(entry)
228	}
229	Exit(1)
230}
231
232func (logger *Logger) Panic(args ...interface{}) {
233	if logger.Level >= PanicLevel {
234		entry := logger.newEntry()
235		entry.Panic(args...)
236		logger.releaseEntry(entry)
237	}
238}
239
240func (logger *Logger) Debugln(args ...interface{}) {
241	if logger.Level >= DebugLevel {
242		entry := logger.newEntry()
243		entry.Debugln(args...)
244		logger.releaseEntry(entry)
245	}
246}
247
248func (logger *Logger) Infoln(args ...interface{}) {
249	if logger.Level >= InfoLevel {
250		entry := logger.newEntry()
251		entry.Infoln(args...)
252		logger.releaseEntry(entry)
253	}
254}
255
256func (logger *Logger) Println(args ...interface{}) {
257	entry := logger.newEntry()
258	entry.Println(args...)
259	logger.releaseEntry(entry)
260}
261
262func (logger *Logger) Warnln(args ...interface{}) {
263	if logger.Level >= WarnLevel {
264		entry := logger.newEntry()
265		entry.Warnln(args...)
266		logger.releaseEntry(entry)
267	}
268}
269
270func (logger *Logger) Warningln(args ...interface{}) {
271	if logger.Level >= WarnLevel {
272		entry := logger.newEntry()
273		entry.Warnln(args...)
274		logger.releaseEntry(entry)
275	}
276}
277
278func (logger *Logger) Errorln(args ...interface{}) {
279	if logger.Level >= ErrorLevel {
280		entry := logger.newEntry()
281		entry.Errorln(args...)
282		logger.releaseEntry(entry)
283	}
284}
285
286func (logger *Logger) Fatalln(args ...interface{}) {
287	if logger.Level >= FatalLevel {
288		entry := logger.newEntry()
289		entry.Fatalln(args...)
290		logger.releaseEntry(entry)
291	}
292	Exit(1)
293}
294
295func (logger *Logger) Panicln(args ...interface{}) {
296	if logger.Level >= PanicLevel {
297		entry := logger.newEntry()
298		entry.Panicln(args...)
299		logger.releaseEntry(entry)
300	}
301}
302
303//When file is opened with appending mode, it's safe to
304//write concurrently to a file (within 4k message on Linux).
305//In these cases user can choose to disable the lock.
306func (logger *Logger) SetNoLock() {
307	logger.mu.Disable()
308}
309