logger.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. package logrus
  2. import (
  3. "io"
  4. "os"
  5. "sync"
  6. "sync/atomic"
  7. "time"
  8. )
  9. type 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 adventurous, 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. // Flag for whether to log caller info (off by default)
  26. ReportCaller bool
  27. // The logging level the logger should log at. This is typically (and defaults
  28. // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
  29. // logged.
  30. Level Level
  31. // Used to sync writing to the log. Locking is enabled by Default
  32. mu MutexWrap
  33. // Reusable empty entry
  34. entryPool sync.Pool
  35. // Function to exit the application, defaults to `os.Exit()`
  36. ExitFunc exitFunc
  37. }
  38. type exitFunc func(int)
  39. type MutexWrap struct {
  40. lock sync.Mutex
  41. disabled bool
  42. }
  43. func (mw *MutexWrap) Lock() {
  44. if !mw.disabled {
  45. mw.lock.Lock()
  46. }
  47. }
  48. func (mw *MutexWrap) Unlock() {
  49. if !mw.disabled {
  50. mw.lock.Unlock()
  51. }
  52. }
  53. func (mw *MutexWrap) Disable() {
  54. mw.disabled = true
  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`.
  68. func New() *Logger {
  69. return &Logger{
  70. Out: os.Stderr,
  71. Formatter: new(TextFormatter),
  72. Hooks: make(LevelHooks),
  73. Level: InfoLevel,
  74. ExitFunc: os.Exit,
  75. ReportCaller: false,
  76. }
  77. }
  78. func (logger *Logger) newEntry() *Entry {
  79. entry, ok := logger.entryPool.Get().(*Entry)
  80. if ok {
  81. return entry
  82. }
  83. return NewEntry(logger)
  84. }
  85. func (logger *Logger) releaseEntry(entry *Entry) {
  86. entry.Data = map[string]interface{}{}
  87. logger.entryPool.Put(entry)
  88. }
  89. // Adds a field to the log entry, note that it doesn't log until you call
  90. // Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
  91. // If you want multiple fields, use `WithFields`.
  92. func (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. // Adds a struct of fields to the log entry. All it does is call `WithField` for
  98. // each `Field`.
  99. func (logger *Logger) WithFields(fields Fields) *Entry {
  100. entry := logger.newEntry()
  101. defer logger.releaseEntry(entry)
  102. return entry.WithFields(fields)
  103. }
  104. // Add an error as single field to the log entry. All it does is call
  105. // `WithError` for the given `error`.
  106. func (logger *Logger) WithError(err error) *Entry {
  107. entry := logger.newEntry()
  108. defer logger.releaseEntry(entry)
  109. return entry.WithError(err)
  110. }
  111. // Overrides the time of the log entry.
  112. func (logger *Logger) WithTime(t time.Time) *Entry {
  113. entry := logger.newEntry()
  114. defer logger.releaseEntry(entry)
  115. return entry.WithTime(t)
  116. }
  117. func (logger *Logger) Tracef(format string, args ...interface{}) {
  118. if logger.IsLevelEnabled(TraceLevel) {
  119. entry := logger.newEntry()
  120. entry.Tracef(format, args...)
  121. logger.releaseEntry(entry)
  122. }
  123. }
  124. func (logger *Logger) Debugf(format string, args ...interface{}) {
  125. if logger.IsLevelEnabled(DebugLevel) {
  126. entry := logger.newEntry()
  127. entry.Debugf(format, args...)
  128. logger.releaseEntry(entry)
  129. }
  130. }
  131. func (logger *Logger) Infof(format string, args ...interface{}) {
  132. if logger.IsLevelEnabled(InfoLevel) {
  133. entry := logger.newEntry()
  134. entry.Infof(format, args...)
  135. logger.releaseEntry(entry)
  136. }
  137. }
  138. func (logger *Logger) Printf(format string, args ...interface{}) {
  139. entry := logger.newEntry()
  140. entry.Printf(format, args...)
  141. logger.releaseEntry(entry)
  142. }
  143. func (logger *Logger) Warnf(format string, args ...interface{}) {
  144. if logger.IsLevelEnabled(WarnLevel) {
  145. entry := logger.newEntry()
  146. entry.Warnf(format, args...)
  147. logger.releaseEntry(entry)
  148. }
  149. }
  150. func (logger *Logger) Warningf(format string, args ...interface{}) {
  151. if logger.IsLevelEnabled(WarnLevel) {
  152. entry := logger.newEntry()
  153. entry.Warnf(format, args...)
  154. logger.releaseEntry(entry)
  155. }
  156. }
  157. func (logger *Logger) Errorf(format string, args ...interface{}) {
  158. if logger.IsLevelEnabled(ErrorLevel) {
  159. entry := logger.newEntry()
  160. entry.Errorf(format, args...)
  161. logger.releaseEntry(entry)
  162. }
  163. }
  164. func (logger *Logger) Fatalf(format string, args ...interface{}) {
  165. if logger.IsLevelEnabled(FatalLevel) {
  166. entry := logger.newEntry()
  167. entry.Fatalf(format, args...)
  168. logger.releaseEntry(entry)
  169. }
  170. logger.Exit(1)
  171. }
  172. func (logger *Logger) Panicf(format string, args ...interface{}) {
  173. if logger.IsLevelEnabled(PanicLevel) {
  174. entry := logger.newEntry()
  175. entry.Panicf(format, args...)
  176. logger.releaseEntry(entry)
  177. }
  178. }
  179. func (logger *Logger) Trace(args ...interface{}) {
  180. if logger.IsLevelEnabled(TraceLevel) {
  181. entry := logger.newEntry()
  182. entry.Trace(args...)
  183. logger.releaseEntry(entry)
  184. }
  185. }
  186. func (logger *Logger) Debug(args ...interface{}) {
  187. if logger.IsLevelEnabled(DebugLevel) {
  188. entry := logger.newEntry()
  189. entry.Debug(args...)
  190. logger.releaseEntry(entry)
  191. }
  192. }
  193. func (logger *Logger) Info(args ...interface{}) {
  194. if logger.IsLevelEnabled(InfoLevel) {
  195. entry := logger.newEntry()
  196. entry.Info(args...)
  197. logger.releaseEntry(entry)
  198. }
  199. }
  200. func (logger *Logger) Print(args ...interface{}) {
  201. entry := logger.newEntry()
  202. entry.Info(args...)
  203. logger.releaseEntry(entry)
  204. }
  205. func (logger *Logger) Warn(args ...interface{}) {
  206. if logger.IsLevelEnabled(WarnLevel) {
  207. entry := logger.newEntry()
  208. entry.Warn(args...)
  209. logger.releaseEntry(entry)
  210. }
  211. }
  212. func (logger *Logger) Warning(args ...interface{}) {
  213. if logger.IsLevelEnabled(WarnLevel) {
  214. entry := logger.newEntry()
  215. entry.Warn(args...)
  216. logger.releaseEntry(entry)
  217. }
  218. }
  219. func (logger *Logger) Error(args ...interface{}) {
  220. if logger.IsLevelEnabled(ErrorLevel) {
  221. entry := logger.newEntry()
  222. entry.Error(args...)
  223. logger.releaseEntry(entry)
  224. }
  225. }
  226. func (logger *Logger) Fatal(args ...interface{}) {
  227. if logger.IsLevelEnabled(FatalLevel) {
  228. entry := logger.newEntry()
  229. entry.Fatal(args...)
  230. logger.releaseEntry(entry)
  231. }
  232. logger.Exit(1)
  233. }
  234. func (logger *Logger) Panic(args ...interface{}) {
  235. if logger.IsLevelEnabled(PanicLevel) {
  236. entry := logger.newEntry()
  237. entry.Panic(args...)
  238. logger.releaseEntry(entry)
  239. }
  240. }
  241. func (logger *Logger) Traceln(args ...interface{}) {
  242. if logger.IsLevelEnabled(TraceLevel) {
  243. entry := logger.newEntry()
  244. entry.Traceln(args...)
  245. logger.releaseEntry(entry)
  246. }
  247. }
  248. func (logger *Logger) Debugln(args ...interface{}) {
  249. if logger.IsLevelEnabled(DebugLevel) {
  250. entry := logger.newEntry()
  251. entry.Debugln(args...)
  252. logger.releaseEntry(entry)
  253. }
  254. }
  255. func (logger *Logger) Infoln(args ...interface{}) {
  256. if logger.IsLevelEnabled(InfoLevel) {
  257. entry := logger.newEntry()
  258. entry.Infoln(args...)
  259. logger.releaseEntry(entry)
  260. }
  261. }
  262. func (logger *Logger) Println(args ...interface{}) {
  263. entry := logger.newEntry()
  264. entry.Println(args...)
  265. logger.releaseEntry(entry)
  266. }
  267. func (logger *Logger) Warnln(args ...interface{}) {
  268. if logger.IsLevelEnabled(WarnLevel) {
  269. entry := logger.newEntry()
  270. entry.Warnln(args...)
  271. logger.releaseEntry(entry)
  272. }
  273. }
  274. func (logger *Logger) Warningln(args ...interface{}) {
  275. if logger.IsLevelEnabled(WarnLevel) {
  276. entry := logger.newEntry()
  277. entry.Warnln(args...)
  278. logger.releaseEntry(entry)
  279. }
  280. }
  281. func (logger *Logger) Errorln(args ...interface{}) {
  282. if logger.IsLevelEnabled(ErrorLevel) {
  283. entry := logger.newEntry()
  284. entry.Errorln(args...)
  285. logger.releaseEntry(entry)
  286. }
  287. }
  288. func (logger *Logger) Fatalln(args ...interface{}) {
  289. if logger.IsLevelEnabled(FatalLevel) {
  290. entry := logger.newEntry()
  291. entry.Fatalln(args...)
  292. logger.releaseEntry(entry)
  293. }
  294. logger.Exit(1)
  295. }
  296. func (logger *Logger) Panicln(args ...interface{}) {
  297. if logger.IsLevelEnabled(PanicLevel) {
  298. entry := logger.newEntry()
  299. entry.Panicln(args...)
  300. logger.releaseEntry(entry)
  301. }
  302. }
  303. func (logger *Logger) Exit(code int) {
  304. runHandlers()
  305. if logger.ExitFunc == nil {
  306. logger.ExitFunc = os.Exit
  307. }
  308. logger.ExitFunc(code)
  309. }
  310. //When file is opened with appending mode, it's safe to
  311. //write concurrently to a file (within 4k message on Linux).
  312. //In these cases user can choose to disable the lock.
  313. func (logger *Logger) SetNoLock() {
  314. logger.mu.Disable()
  315. }
  316. func (logger *Logger) level() Level {
  317. return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
  318. }
  319. // SetLevel sets the logger level.
  320. func (logger *Logger) SetLevel(level Level) {
  321. atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
  322. }
  323. // GetLevel returns the logger level.
  324. func (logger *Logger) GetLevel() Level {
  325. return logger.level()
  326. }
  327. // AddHook adds a hook to the logger hooks.
  328. func (logger *Logger) AddHook(hook Hook) {
  329. logger.mu.Lock()
  330. defer logger.mu.Unlock()
  331. logger.Hooks.Add(hook)
  332. }
  333. // IsLevelEnabled checks if the log level of the logger is greater than the level param
  334. func (logger *Logger) IsLevelEnabled(level Level) bool {
  335. return logger.level() >= level
  336. }
  337. // SetFormatter sets the logger formatter.
  338. func (logger *Logger) SetFormatter(formatter Formatter) {
  339. logger.mu.Lock()
  340. defer logger.mu.Unlock()
  341. logger.Formatter = formatter
  342. }
  343. // SetOutput sets the logger output.
  344. func (logger *Logger) SetOutput(output io.Writer) {
  345. logger.mu.Lock()
  346. defer logger.mu.Unlock()
  347. logger.Out = output
  348. }
  349. func (logger *Logger) SetReportCaller(reportCaller bool) {
  350. logger.mu.Lock()
  351. defer logger.mu.Unlock()
  352. logger.ReportCaller = reportCaller
  353. }
  354. // ReplaceHooks replaces the logger hooks and returns the old ones
  355. func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
  356. logger.mu.Lock()
  357. oldHooks := logger.Hooks
  358. logger.Hooks = hooks
  359. logger.mu.Unlock()
  360. return oldHooks
  361. }