logger.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // Copyright (C) 2014 Jakob Borg. All rights reserved. Use of this source code
  2. // is governed by an MIT-style license that can be found in the LICENSE file.
  3. // Package logger implements a standardized logger with callback functionality
  4. package logger
  5. import (
  6. "fmt"
  7. "io/ioutil"
  8. "log"
  9. "os"
  10. "strings"
  11. "sync"
  12. )
  13. type LogLevel int
  14. const (
  15. LevelDebug LogLevel = iota
  16. LevelVerbose
  17. LevelInfo
  18. LevelOK
  19. LevelWarn
  20. LevelFatal
  21. NumLevels
  22. )
  23. // A MessageHandler is called with the log level and message text.
  24. type MessageHandler func(l LogLevel, msg string)
  25. type Logger interface {
  26. AddHandler(level LogLevel, h MessageHandler)
  27. SetFlags(flag int)
  28. SetPrefix(prefix string)
  29. Debugln(vals ...interface{})
  30. Debugf(format string, vals ...interface{})
  31. Verboseln(vals ...interface{})
  32. Verbosef(format string, vals ...interface{})
  33. Infoln(vals ...interface{})
  34. Infof(format string, vals ...interface{})
  35. Okln(vals ...interface{})
  36. Okf(format string, vals ...interface{})
  37. Warnln(vals ...interface{})
  38. Warnf(format string, vals ...interface{})
  39. Fatalln(vals ...interface{})
  40. Fatalf(format string, vals ...interface{})
  41. ShouldDebug(facility string) bool
  42. SetDebug(facility string, enabled bool)
  43. Facilities() (enabled, disabled []string)
  44. NewFacility(facility string) Logger
  45. }
  46. type logger struct {
  47. logger *log.Logger
  48. handlers [NumLevels][]MessageHandler
  49. debug map[string]bool
  50. mut sync.Mutex
  51. }
  52. // The default logger logs to standard output with a time prefix.
  53. var DefaultLogger = New()
  54. func New() Logger {
  55. if os.Getenv("LOGGER_DISCARD") != "" {
  56. // Hack to completely disable logging, for example when running benchmarks.
  57. return &logger{
  58. logger: log.New(ioutil.Discard, "", 0),
  59. }
  60. }
  61. return &logger{
  62. logger: log.New(os.Stdout, "", log.Ltime),
  63. }
  64. }
  65. // AddHandler registers a new MessageHandler to receive messages with the
  66. // specified log level or above.
  67. func (l *logger) AddHandler(level LogLevel, h MessageHandler) {
  68. l.mut.Lock()
  69. defer l.mut.Unlock()
  70. l.handlers[level] = append(l.handlers[level], h)
  71. }
  72. // See log.SetFlags
  73. func (l *logger) SetFlags(flag int) {
  74. l.logger.SetFlags(flag)
  75. }
  76. // See log.SetPrefix
  77. func (l *logger) SetPrefix(prefix string) {
  78. l.logger.SetPrefix(prefix)
  79. }
  80. func (l *logger) callHandlers(level LogLevel, s string) {
  81. for ll := LevelDebug; ll <= level; ll++ {
  82. for _, h := range l.handlers[ll] {
  83. h(level, strings.TrimSpace(s))
  84. }
  85. }
  86. }
  87. // Debugln logs a line with a DEBUG prefix.
  88. func (l *logger) Debugln(vals ...interface{}) {
  89. l.mut.Lock()
  90. defer l.mut.Unlock()
  91. s := fmt.Sprintln(vals...)
  92. l.logger.Output(2, "DEBUG: "+s)
  93. l.callHandlers(LevelDebug, s)
  94. }
  95. // Debugf logs a formatted line with a DEBUG prefix.
  96. func (l *logger) Debugf(format string, vals ...interface{}) {
  97. l.mut.Lock()
  98. defer l.mut.Unlock()
  99. s := fmt.Sprintf(format, vals...)
  100. l.logger.Output(2, "DEBUG: "+s)
  101. l.callHandlers(LevelDebug, s)
  102. }
  103. // Infoln logs a line with a VERBOSE prefix.
  104. func (l *logger) Verboseln(vals ...interface{}) {
  105. l.mut.Lock()
  106. defer l.mut.Unlock()
  107. s := fmt.Sprintln(vals...)
  108. l.logger.Output(2, "VERBOSE: "+s)
  109. l.callHandlers(LevelVerbose, s)
  110. }
  111. // Infof logs a formatted line with a VERBOSE prefix.
  112. func (l *logger) Verbosef(format string, vals ...interface{}) {
  113. l.mut.Lock()
  114. defer l.mut.Unlock()
  115. s := fmt.Sprintf(format, vals...)
  116. l.logger.Output(2, "VERBOSE: "+s)
  117. l.callHandlers(LevelVerbose, s)
  118. }
  119. // Infoln logs a line with an INFO prefix.
  120. func (l *logger) Infoln(vals ...interface{}) {
  121. l.mut.Lock()
  122. defer l.mut.Unlock()
  123. s := fmt.Sprintln(vals...)
  124. l.logger.Output(2, "INFO: "+s)
  125. l.callHandlers(LevelInfo, s)
  126. }
  127. // Infof logs a formatted line with an INFO prefix.
  128. func (l *logger) Infof(format string, vals ...interface{}) {
  129. l.mut.Lock()
  130. defer l.mut.Unlock()
  131. s := fmt.Sprintf(format, vals...)
  132. l.logger.Output(2, "INFO: "+s)
  133. l.callHandlers(LevelInfo, s)
  134. }
  135. // Okln logs a line with an OK prefix.
  136. func (l *logger) Okln(vals ...interface{}) {
  137. l.mut.Lock()
  138. defer l.mut.Unlock()
  139. s := fmt.Sprintln(vals...)
  140. l.logger.Output(2, "OK: "+s)
  141. l.callHandlers(LevelOK, s)
  142. }
  143. // Okf logs a formatted line with an OK prefix.
  144. func (l *logger) Okf(format string, vals ...interface{}) {
  145. l.mut.Lock()
  146. defer l.mut.Unlock()
  147. s := fmt.Sprintf(format, vals...)
  148. l.logger.Output(2, "OK: "+s)
  149. l.callHandlers(LevelOK, s)
  150. }
  151. // Warnln logs a formatted line with a WARNING prefix.
  152. func (l *logger) Warnln(vals ...interface{}) {
  153. l.mut.Lock()
  154. defer l.mut.Unlock()
  155. s := fmt.Sprintln(vals...)
  156. l.logger.Output(2, "WARNING: "+s)
  157. l.callHandlers(LevelWarn, s)
  158. }
  159. // Warnf logs a formatted line with a WARNING prefix.
  160. func (l *logger) Warnf(format string, vals ...interface{}) {
  161. l.mut.Lock()
  162. defer l.mut.Unlock()
  163. s := fmt.Sprintf(format, vals...)
  164. l.logger.Output(2, "WARNING: "+s)
  165. l.callHandlers(LevelWarn, s)
  166. }
  167. // Fatalln logs a line with a FATAL prefix and exits the process with exit
  168. // code 1.
  169. func (l *logger) Fatalln(vals ...interface{}) {
  170. l.mut.Lock()
  171. defer l.mut.Unlock()
  172. s := fmt.Sprintln(vals...)
  173. l.logger.Output(2, "FATAL: "+s)
  174. l.callHandlers(LevelFatal, s)
  175. os.Exit(1)
  176. }
  177. // Fatalf logs a formatted line with a FATAL prefix and exits the process with
  178. // exit code 1.
  179. func (l *logger) Fatalf(format string, vals ...interface{}) {
  180. l.mut.Lock()
  181. defer l.mut.Unlock()
  182. s := fmt.Sprintf(format, vals...)
  183. l.logger.Output(2, "FATAL: "+s)
  184. l.callHandlers(LevelFatal, s)
  185. os.Exit(1)
  186. }
  187. // ShouldDebug returns true if the given facility has debugging enabled.
  188. func (l *logger) ShouldDebug(facility string) bool {
  189. l.mut.Lock()
  190. res := l.debug[facility]
  191. l.mut.Unlock()
  192. return res
  193. }
  194. // SetDebug enabled or disables debugging for the given facility name.
  195. func (l *logger) SetDebug(facility string, enabled bool) {
  196. l.mut.Lock()
  197. l.debug[facility] = enabled
  198. l.mut.Unlock()
  199. }
  200. // Facilities returns the currently known set of facilities, both those for
  201. // which debug is enabled and those for which it is disabled.
  202. func (l *logger) Facilities() (enabled, disabled []string) {
  203. l.mut.Lock()
  204. for facility, isEnabled := range l.debug {
  205. if isEnabled {
  206. enabled = append(enabled, facility)
  207. } else {
  208. disabled = append(disabled, facility)
  209. }
  210. }
  211. l.mut.Unlock()
  212. return
  213. }
  214. // NewFacility returns a new logger bound to the named facility.
  215. func (l *logger) NewFacility(facility string) Logger {
  216. l.mut.Lock()
  217. if l.debug == nil {
  218. l.debug = make(map[string]bool)
  219. }
  220. l.debug[facility] = false
  221. l.mut.Unlock()
  222. return &facilityLogger{
  223. logger: l,
  224. facility: facility,
  225. }
  226. }
  227. // A facilityLogger is a regular logger but bound to a facility name. The
  228. // Debugln and Debugf methods are no-ops unless debugging has been enabled for
  229. // this facility on the parent logger.
  230. type facilityLogger struct {
  231. *logger
  232. facility string
  233. }
  234. // Debugln logs a line with a DEBUG prefix.
  235. func (l *facilityLogger) Debugln(vals ...interface{}) {
  236. if !l.ShouldDebug(l.facility) {
  237. return
  238. }
  239. l.logger.Debugln(vals...)
  240. }
  241. // Debugf logs a formatted line with a DEBUG prefix.
  242. func (l *facilityLogger) Debugf(format string, vals ...interface{}) {
  243. if !l.ShouldDebug(l.facility) {
  244. return
  245. }
  246. l.logger.Debugf(format, vals...)
  247. }