You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

logger.go 8.8KB

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