blob: 370fff5d1ba5b210a12be36e28bb5fe65ed6da2d [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001package 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}