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