logger.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. package golog
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "sync"
  7. "time"
  8. "github.com/kataras/pio"
  9. )
  10. // Handler is the signature type for logger's handler.
  11. //
  12. // A Handler can be used to intercept the message between a log value
  13. // and the actual print operation, it's called
  14. // when one of the print functions called.
  15. // If it's return value is true then it means that the specific
  16. // handler handled the log by itself therefore no need to
  17. // proceed with the default behavior of printing the log
  18. // to the specified logger's output.
  19. //
  20. // It stops on the handler which returns true firstly.
  21. // The `Log` value holds the level of the print operation as well.
  22. type Handler func(value *Log) (handled bool)
  23. // Logger is our golog.
  24. type Logger struct {
  25. Prefix []byte
  26. Level Level
  27. TimeFormat string
  28. // if new line should be added on all log functions, even the `F`s.
  29. // It defaults to true.
  30. //
  31. // See `golog#NewLine(newLineChar string)` as well.
  32. //
  33. // Note that this will not override the time and level prefix,
  34. // if you want to customize the log message please read the examples
  35. // or navigate to: https://github.com/kataras/golog/issues/3#issuecomment-355895870.
  36. NewLine bool
  37. mu sync.Mutex
  38. Printer *pio.Printer
  39. handlers []Handler
  40. once sync.Once
  41. logs sync.Pool
  42. children *loggerMap
  43. }
  44. // New returns a new golog with a default output to `os.Stdout`
  45. // and level to `InfoLevel`.
  46. func New() *Logger {
  47. return &Logger{
  48. Level: InfoLevel,
  49. TimeFormat: "2006/01/02 15:04",
  50. NewLine: true,
  51. Printer: pio.NewPrinter("", os.Stdout).EnableDirectOutput().Hijack(logHijacker),
  52. children: newLoggerMap(),
  53. }
  54. }
  55. // acquireLog returns a new log fom the pool.
  56. func (l *Logger) acquireLog(level Level, msg string, withPrintln bool) *Log {
  57. log, ok := l.logs.Get().(*Log)
  58. if !ok {
  59. log = &Log{
  60. Logger: l,
  61. }
  62. }
  63. log.NewLine = withPrintln
  64. log.Time = time.Now()
  65. log.Level = level
  66. log.Message = msg
  67. return log
  68. }
  69. // releaseLog Log releases a log instance back to the pool.
  70. func (l *Logger) releaseLog(log *Log) {
  71. l.logs.Put(log)
  72. }
  73. // we could use marshal inside Log but we don't have access to printer,
  74. // we could also use the .Handle with NopOutput too but
  75. // this way is faster:
  76. var logHijacker = func(ctx *pio.Ctx) {
  77. l, ok := ctx.Value.(*Log)
  78. if !ok {
  79. ctx.Next()
  80. return
  81. }
  82. line := GetTextForLevel(l.Level, ctx.Printer.IsTerminal)
  83. if line != "" {
  84. line += " "
  85. }
  86. if t := l.FormatTime(); t != "" {
  87. line += t + " "
  88. }
  89. line += l.Message
  90. var b []byte
  91. if pref := l.Logger.Prefix; len(pref) > 0 {
  92. b = append(pref, []byte(line)...)
  93. } else {
  94. b = []byte(line)
  95. }
  96. ctx.Store(b, nil)
  97. ctx.Next()
  98. }
  99. // NopOutput disables the output.
  100. var NopOutput = pio.NopOutput()
  101. // SetOutput overrides the Logger's Printer's Output with another `io.Writer`.
  102. //
  103. // Returns itself.
  104. func (l *Logger) SetOutput(w io.Writer) *Logger {
  105. l.Printer.SetOutput(w)
  106. return l
  107. }
  108. // AddOutput adds one or more `io.Writer` to the Logger's Printer.
  109. //
  110. // If one of the "writers" is not a terminal-based (i.e File)
  111. // then colors will be disabled for all outputs.
  112. //
  113. // Returns itself.
  114. func (l *Logger) AddOutput(writers ...io.Writer) *Logger {
  115. l.Printer.AddOutput(writers...)
  116. return l
  117. }
  118. // SetPrefix sets a prefix for this "l" Logger.
  119. //
  120. // The prefix is the first space-separated
  121. // word that is being presented to the output.
  122. // It's written even before the log level text.
  123. //
  124. // Returns itself.
  125. func (l *Logger) SetPrefix(s string) *Logger {
  126. l.mu.Lock()
  127. l.Prefix = []byte(s)
  128. l.mu.Unlock()
  129. return l
  130. }
  131. // SetTimeFormat sets time format for logs,
  132. // if "s" is empty then time representation will be off.
  133. //
  134. // Returns itself.
  135. func (l *Logger) SetTimeFormat(s string) *Logger {
  136. l.mu.Lock()
  137. l.TimeFormat = s
  138. l.mu.Unlock()
  139. return l
  140. }
  141. // DisableNewLine disables the new line suffix on every log function, even the `F`'s,
  142. // the caller should add "\n" to the log message manually after this call.
  143. //
  144. // Returns itself.
  145. func (l *Logger) DisableNewLine() *Logger {
  146. l.mu.Lock()
  147. l.NewLine = false
  148. l.mu.Unlock()
  149. return l
  150. }
  151. // SetLevel accepts a string representation of
  152. // a `Level` and returns a `Level` value based on that "levelName".
  153. //
  154. // Available level names are:
  155. // "disable"
  156. // "fatal"
  157. // "error"
  158. // "warn"
  159. // "info"
  160. // "debug"
  161. //
  162. // Alternatively you can use the exported `Level` field, i.e `Level = golog.ErrorLevel`
  163. //
  164. // Returns itself.
  165. func (l *Logger) SetLevel(levelName string) *Logger {
  166. l.mu.Lock()
  167. l.Level = fromLevelName(levelName)
  168. l.mu.Unlock()
  169. return l
  170. }
  171. func (l *Logger) print(level Level, msg string, newLine bool) {
  172. if l.Level >= level {
  173. // newLine passed here in order for handler to know
  174. // if this message derives from Println and Leveled functions
  175. // or by simply, Print.
  176. log := l.acquireLog(level, msg, newLine)
  177. // if not handled by one of the handler
  178. // then print it as usual.
  179. if !l.handled(log) {
  180. if newLine {
  181. l.Printer.Println(log)
  182. } else {
  183. l.Printer.Print(log)
  184. }
  185. }
  186. l.releaseLog(log)
  187. }
  188. // if level was fatal we don't care about the logger's level, we'll exit.
  189. if level == FatalLevel {
  190. os.Exit(1)
  191. }
  192. }
  193. // Print prints a log message without levels and colors.
  194. func (l *Logger) Print(v ...interface{}) {
  195. l.print(DisableLevel, fmt.Sprint(v...), l.NewLine)
  196. }
  197. // Printf formats according to a format specifier and writes to `Printer#Output` without levels and colors.
  198. func (l *Logger) Printf(format string, args ...interface{}) {
  199. l.print(DisableLevel, fmt.Sprintf(format, args...), l.NewLine)
  200. }
  201. // Println prints a log message without levels and colors.
  202. // It adds a new line at the end, it overrides the `NewLine` option.
  203. func (l *Logger) Println(v ...interface{}) {
  204. l.print(DisableLevel, fmt.Sprint(v...), true)
  205. }
  206. // Log prints a leveled log message to the output.
  207. // This method can be used to use custom log levels if needed.
  208. // It adds a new line in the end.
  209. func (l *Logger) Log(level Level, v ...interface{}) {
  210. l.print(level, fmt.Sprint(v...), l.NewLine)
  211. }
  212. // Logf prints a leveled log message to the output.
  213. // This method can be used to use custom log levels if needed.
  214. // It adds a new line in the end.
  215. func (l *Logger) Logf(level Level, format string, args ...interface{}) {
  216. msg := fmt.Sprintf(format, args...)
  217. l.Log(level, msg)
  218. }
  219. // Fatal `os.Exit(1)` exit no matter the level of the logger.
  220. // If the logger's level is fatal, error, warn, info or debug
  221. // then it will print the log message too.
  222. func (l *Logger) Fatal(v ...interface{}) {
  223. l.Log(FatalLevel, v...)
  224. }
  225. // Fatalf will `os.Exit(1)` no matter the level of the logger.
  226. // If the logger's level is fatal, error, warn, info or debug
  227. // then it will print the log message too.
  228. func (l *Logger) Fatalf(format string, args ...interface{}) {
  229. msg := fmt.Sprintf(format, args...)
  230. l.Fatal(msg)
  231. }
  232. // Error will print only when logger's Level is error, warn, info or debug.
  233. func (l *Logger) Error(v ...interface{}) {
  234. l.Log(ErrorLevel, v...)
  235. }
  236. // Errorf will print only when logger's Level is error, warn, info or debug.
  237. func (l *Logger) Errorf(format string, args ...interface{}) {
  238. msg := fmt.Sprintf(format, args...)
  239. l.Error(msg)
  240. }
  241. // Warn will print when logger's Level is warn, info or debug.
  242. func (l *Logger) Warn(v ...interface{}) {
  243. l.Log(WarnLevel, v...)
  244. }
  245. // Warnf will print when logger's Level is warn, info or debug.
  246. func (l *Logger) Warnf(format string, args ...interface{}) {
  247. msg := fmt.Sprintf(format, args...)
  248. l.Warn(msg)
  249. }
  250. // Info will print when logger's Level is info or debug.
  251. func (l *Logger) Info(v ...interface{}) {
  252. l.Log(InfoLevel, v...)
  253. }
  254. // Infof will print when logger's Level is info or debug.
  255. func (l *Logger) Infof(format string, args ...interface{}) {
  256. msg := fmt.Sprintf(format, args...)
  257. l.Info(msg)
  258. }
  259. // Debug will print when logger's Level is debug.
  260. func (l *Logger) Debug(v ...interface{}) {
  261. l.Log(DebugLevel, v...)
  262. }
  263. // Debugf will print when logger's Level is debug.
  264. func (l *Logger) Debugf(format string, args ...interface{}) {
  265. // On debug mode don't even try to fmt.Sprintf if it's not required,
  266. // this can be used to allow `Debugf` to be called without even the `fmt.Sprintf`'s
  267. // performance cost if the logger doesn't allow debug logging.
  268. if l.Level >= DebugLevel {
  269. msg := fmt.Sprintf(format, args...)
  270. l.Debug(msg)
  271. }
  272. }
  273. // Install receives an external logger
  274. // and automatically adapts its print functions.
  275. //
  276. // Install adds a golog handler to support third-party integrations,
  277. // it can be used only once per `golog#Logger` instance.
  278. //
  279. // For example, if you want to print using a logrus
  280. // logger you can do the following:
  281. // `Install(logrus.StandardLogger())`
  282. //
  283. // Look `golog#Logger.Handle` for more.
  284. func (l *Logger) Install(logger ExternalLogger) {
  285. l.Handle(integrateExternalLogger(logger))
  286. }
  287. // InstallStd receives a standard logger
  288. // and automatically adapts its print functions.
  289. //
  290. // Install adds a golog handler to support third-party integrations,
  291. // it can be used only once per `golog#Logger` instance.
  292. //
  293. // Example Code:
  294. // import "log"
  295. // myLogger := log.New(os.Stdout, "", 0)
  296. // InstallStd(myLogger)
  297. //
  298. // Look `golog#Logger.Handle` for more.
  299. func (l *Logger) InstallStd(logger StdLogger) {
  300. l.Handle(integrateStdLogger(logger))
  301. }
  302. // Handle adds a log handler.
  303. //
  304. // Handlers can be used to intercept the message between a log value
  305. // and the actual print operation, it's called
  306. // when one of the print functions called.
  307. // If it's return value is true then it means that the specific
  308. // handler handled the log by itself therefore no need to
  309. // proceed with the default behavior of printing the log
  310. // to the specified logger's output.
  311. //
  312. // It stops on the handler which returns true firstly.
  313. // The `Log` value holds the level of the print operation as well.
  314. func (l *Logger) Handle(handler Handler) {
  315. l.mu.Lock()
  316. l.handlers = append(l.handlers, handler)
  317. l.mu.Unlock()
  318. }
  319. func (l *Logger) handled(value *Log) (handled bool) {
  320. for _, h := range l.handlers {
  321. if h(value) {
  322. return true
  323. }
  324. }
  325. return false
  326. }
  327. // Hijack adds a hijacker to the low-level logger's Printer.
  328. // If you need to implement such as a low-level hijacker manually,
  329. // then you have to make use of the pio library.
  330. func (l *Logger) Hijack(hijacker func(ctx *pio.Ctx)) {
  331. l.Printer.Hijack(hijacker)
  332. }
  333. // Scan scans everything from "r" and prints
  334. // its new contents to the logger's Printer's Output,
  335. // forever or until the returning "cancel" is fired, once.
  336. func (l *Logger) Scan(r io.Reader) (cancel func()) {
  337. l.once.Do(func() {
  338. // add a marshaler once
  339. // in order to handle []byte and string
  340. // as its input.
  341. // Because scan doesn't care about
  342. // logging levels (because of the io.Reader)
  343. // Note: We don't use the `pio.Text` built'n marshaler
  344. // because we want to manage time log too.
  345. l.Printer.MarshalFunc(func(v interface{}) ([]byte, error) {
  346. var line []byte
  347. if b, ok := v.([]byte); ok {
  348. line = b
  349. } else if s, ok := v.(string); ok {
  350. line = []byte(s)
  351. }
  352. if len(line) == 0 {
  353. return nil, pio.ErrMarshalNotResponsible
  354. }
  355. formattedTime := time.Now().Format(l.TimeFormat)
  356. if formattedTime != "" {
  357. line = append([]byte(formattedTime+" "), line...)
  358. }
  359. return line, nil
  360. })
  361. })
  362. return l.Printer.Scan(r, true)
  363. }
  364. // Clone returns a copy of this "l" Logger.
  365. // This copy is returned as pointer as well.
  366. func (l *Logger) Clone() *Logger {
  367. return &Logger{
  368. Prefix: l.Prefix,
  369. Level: l.Level,
  370. TimeFormat: l.TimeFormat,
  371. Printer: l.Printer,
  372. handlers: l.handlers,
  373. children: newLoggerMap(),
  374. mu: sync.Mutex{},
  375. once: sync.Once{},
  376. }
  377. }
  378. // Child (creates if not exists and) returns a new child
  379. // Logger based on the "l"'s fields.
  380. //
  381. // Can be used to separate logs by category.
  382. func (l *Logger) Child(name string) *Logger {
  383. return l.children.getOrAdd(name, l)
  384. }
  385. type loggerMap struct {
  386. mu sync.RWMutex
  387. Items map[string]*Logger
  388. }
  389. func newLoggerMap() *loggerMap {
  390. return &loggerMap{
  391. Items: make(map[string]*Logger),
  392. }
  393. }
  394. func (m *loggerMap) getOrAdd(name string, parent *Logger) *Logger {
  395. m.mu.RLock()
  396. logger, ok := m.Items[name]
  397. m.mu.RUnlock()
  398. if ok {
  399. return logger
  400. }
  401. logger = parent.Clone()
  402. prefix := name
  403. // if prefix doesn't end with a whitespace, then add it here.
  404. if lb := name[len(prefix)-1]; lb != ' ' {
  405. prefix += ": "
  406. }
  407. logger.SetPrefix(prefix)
  408. m.mu.Lock()
  409. m.Items[name] = logger
  410. m.mu.Unlock()
  411. return logger
  412. }