logger.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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. "time"
  13. )
  14. // This package uses stdlib sync as it may be used to debug syncthing/lib/sync
  15. // and that would cause an implosion of the universe.
  16. type LogLevel int
  17. const (
  18. LevelDebug LogLevel = iota
  19. LevelVerbose
  20. LevelInfo
  21. LevelOK
  22. LevelWarn
  23. LevelFatal
  24. NumLevels
  25. )
  26. // A MessageHandler is called with the log level and message text.
  27. type MessageHandler func(l LogLevel, msg string)
  28. type Logger interface {
  29. AddHandler(level LogLevel, h MessageHandler)
  30. SetFlags(flag int)
  31. SetPrefix(prefix string)
  32. Debugln(vals ...interface{})
  33. Debugf(format string, vals ...interface{})
  34. Verboseln(vals ...interface{})
  35. Verbosef(format string, vals ...interface{})
  36. Infoln(vals ...interface{})
  37. Infof(format string, vals ...interface{})
  38. Okln(vals ...interface{})
  39. Okf(format string, vals ...interface{})
  40. Warnln(vals ...interface{})
  41. Warnf(format string, vals ...interface{})
  42. Fatalln(vals ...interface{})
  43. Fatalf(format string, vals ...interface{})
  44. ShouldDebug(facility string) bool
  45. SetDebug(facility string, enabled bool)
  46. Facilities() map[string]string
  47. FacilityDebugging() []string
  48. NewFacility(facility, description string) Logger
  49. }
  50. type logger struct {
  51. logger *log.Logger
  52. handlers [NumLevels][]MessageHandler
  53. facilities map[string]string // facility name => description
  54. debug map[string]bool // facility name => debugging enabled
  55. mut sync.Mutex
  56. }
  57. // The default logger logs to standard output with a time prefix.
  58. var DefaultLogger = New()
  59. func New() Logger {
  60. if os.Getenv("LOGGER_DISCARD") != "" {
  61. // Hack to completely disable logging, for example when running benchmarks.
  62. return &logger{
  63. logger: log.New(ioutil.Discard, "", 0),
  64. }
  65. }
  66. return &logger{
  67. logger: log.New(os.Stdout, "", log.Ltime),
  68. }
  69. }
  70. // AddHandler registers a new MessageHandler to receive messages with the
  71. // specified log level or above.
  72. func (l *logger) AddHandler(level LogLevel, h MessageHandler) {
  73. l.mut.Lock()
  74. defer l.mut.Unlock()
  75. l.handlers[level] = append(l.handlers[level], h)
  76. }
  77. // See log.SetFlags
  78. func (l *logger) SetFlags(flag int) {
  79. l.logger.SetFlags(flag)
  80. }
  81. // See log.SetPrefix
  82. func (l *logger) SetPrefix(prefix string) {
  83. l.logger.SetPrefix(prefix)
  84. }
  85. func (l *logger) callHandlers(level LogLevel, s string) {
  86. for ll := LevelDebug; ll <= level; ll++ {
  87. for _, h := range l.handlers[ll] {
  88. h(level, strings.TrimSpace(s))
  89. }
  90. }
  91. }
  92. // Debugln logs a line with a DEBUG prefix.
  93. func (l *logger) Debugln(vals ...interface{}) {
  94. l.debugln(3, vals)
  95. }
  96. func (l *logger) debugln(level int, vals ...interface{}) {
  97. l.mut.Lock()
  98. defer l.mut.Unlock()
  99. s := fmt.Sprintln(vals...)
  100. l.logger.Output(level, "DEBUG: "+s)
  101. l.callHandlers(LevelDebug, s)
  102. }
  103. // Debugf logs a formatted line with a DEBUG prefix.
  104. func (l *logger) Debugf(format string, vals ...interface{}) {
  105. l.debugf(3, format, vals...)
  106. }
  107. func (l *logger) debugf(level int, format string, vals ...interface{}) {
  108. l.mut.Lock()
  109. defer l.mut.Unlock()
  110. s := fmt.Sprintf(format, vals...)
  111. l.logger.Output(level, "DEBUG: "+s)
  112. l.callHandlers(LevelDebug, s)
  113. }
  114. // Infoln logs a line with a VERBOSE prefix.
  115. func (l *logger) Verboseln(vals ...interface{}) {
  116. l.mut.Lock()
  117. defer l.mut.Unlock()
  118. s := fmt.Sprintln(vals...)
  119. l.logger.Output(2, "VERBOSE: "+s)
  120. l.callHandlers(LevelVerbose, s)
  121. }
  122. // Infof logs a formatted line with a VERBOSE prefix.
  123. func (l *logger) Verbosef(format string, vals ...interface{}) {
  124. l.mut.Lock()
  125. defer l.mut.Unlock()
  126. s := fmt.Sprintf(format, vals...)
  127. l.logger.Output(2, "VERBOSE: "+s)
  128. l.callHandlers(LevelVerbose, s)
  129. }
  130. // Infoln logs a line with an INFO prefix.
  131. func (l *logger) Infoln(vals ...interface{}) {
  132. l.mut.Lock()
  133. defer l.mut.Unlock()
  134. s := fmt.Sprintln(vals...)
  135. l.logger.Output(2, "INFO: "+s)
  136. l.callHandlers(LevelInfo, s)
  137. }
  138. // Infof logs a formatted line with an INFO prefix.
  139. func (l *logger) Infof(format string, vals ...interface{}) {
  140. l.mut.Lock()
  141. defer l.mut.Unlock()
  142. s := fmt.Sprintf(format, vals...)
  143. l.logger.Output(2, "INFO: "+s)
  144. l.callHandlers(LevelInfo, s)
  145. }
  146. // Okln logs a line with an OK prefix.
  147. func (l *logger) Okln(vals ...interface{}) {
  148. l.mut.Lock()
  149. defer l.mut.Unlock()
  150. s := fmt.Sprintln(vals...)
  151. l.logger.Output(2, "OK: "+s)
  152. l.callHandlers(LevelOK, s)
  153. }
  154. // Okf logs a formatted line with an OK prefix.
  155. func (l *logger) Okf(format string, vals ...interface{}) {
  156. l.mut.Lock()
  157. defer l.mut.Unlock()
  158. s := fmt.Sprintf(format, vals...)
  159. l.logger.Output(2, "OK: "+s)
  160. l.callHandlers(LevelOK, s)
  161. }
  162. // Warnln logs a formatted line with a WARNING prefix.
  163. func (l *logger) Warnln(vals ...interface{}) {
  164. l.mut.Lock()
  165. defer l.mut.Unlock()
  166. s := fmt.Sprintln(vals...)
  167. l.logger.Output(2, "WARNING: "+s)
  168. l.callHandlers(LevelWarn, s)
  169. }
  170. // Warnf logs a formatted line with a WARNING prefix.
  171. func (l *logger) Warnf(format string, vals ...interface{}) {
  172. l.mut.Lock()
  173. defer l.mut.Unlock()
  174. s := fmt.Sprintf(format, vals...)
  175. l.logger.Output(2, "WARNING: "+s)
  176. l.callHandlers(LevelWarn, s)
  177. }
  178. // Fatalln logs a line with a FATAL prefix and exits the process with exit
  179. // code 1.
  180. func (l *logger) Fatalln(vals ...interface{}) {
  181. l.mut.Lock()
  182. defer l.mut.Unlock()
  183. s := fmt.Sprintln(vals...)
  184. l.logger.Output(2, "FATAL: "+s)
  185. l.callHandlers(LevelFatal, s)
  186. os.Exit(1)
  187. }
  188. // Fatalf logs a formatted line with a FATAL prefix and exits the process with
  189. // exit code 1.
  190. func (l *logger) Fatalf(format string, vals ...interface{}) {
  191. l.mut.Lock()
  192. defer l.mut.Unlock()
  193. s := fmt.Sprintf(format, vals...)
  194. l.logger.Output(2, "FATAL: "+s)
  195. l.callHandlers(LevelFatal, s)
  196. os.Exit(1)
  197. }
  198. // ShouldDebug returns true if the given facility has debugging enabled.
  199. func (l *logger) ShouldDebug(facility string) bool {
  200. l.mut.Lock()
  201. res := l.debug[facility]
  202. l.mut.Unlock()
  203. return res
  204. }
  205. // SetDebug enabled or disables debugging for the given facility name.
  206. func (l *logger) SetDebug(facility string, enabled bool) {
  207. l.mut.Lock()
  208. l.debug[facility] = enabled
  209. l.mut.Unlock()
  210. }
  211. // FacilityDebugging returns the set of facilities that have debugging
  212. // enabled.
  213. func (l *logger) FacilityDebugging() []string {
  214. var enabled []string
  215. l.mut.Lock()
  216. for facility, isEnabled := range l.debug {
  217. if isEnabled {
  218. enabled = append(enabled, facility)
  219. }
  220. }
  221. l.mut.Unlock()
  222. return enabled
  223. }
  224. // Facilities returns the currently known set of facilities and their
  225. // descriptions.
  226. func (l *logger) Facilities() map[string]string {
  227. l.mut.Lock()
  228. res := make(map[string]string, len(l.facilities))
  229. for facility, descr := range l.facilities {
  230. res[facility] = descr
  231. }
  232. l.mut.Unlock()
  233. return res
  234. }
  235. // NewFacility returns a new logger bound to the named facility.
  236. func (l *logger) NewFacility(facility, description string) Logger {
  237. l.mut.Lock()
  238. if l.facilities == nil {
  239. l.facilities = make(map[string]string)
  240. }
  241. if description != "" {
  242. l.facilities[facility] = description
  243. }
  244. if l.debug == nil {
  245. l.debug = make(map[string]bool)
  246. }
  247. l.debug[facility] = false
  248. l.mut.Unlock()
  249. return &facilityLogger{
  250. logger: l,
  251. facility: facility,
  252. }
  253. }
  254. // A facilityLogger is a regular logger but bound to a facility name. The
  255. // Debugln and Debugf methods are no-ops unless debugging has been enabled for
  256. // this facility on the parent logger.
  257. type facilityLogger struct {
  258. *logger
  259. facility string
  260. }
  261. // Debugln logs a line with a DEBUG prefix.
  262. func (l *facilityLogger) Debugln(vals ...interface{}) {
  263. if !l.ShouldDebug(l.facility) {
  264. return
  265. }
  266. l.logger.debugln(3, vals...)
  267. }
  268. // Debugf logs a formatted line with a DEBUG prefix.
  269. func (l *facilityLogger) Debugf(format string, vals ...interface{}) {
  270. if !l.ShouldDebug(l.facility) {
  271. return
  272. }
  273. l.logger.debugf(3, format, vals...)
  274. }
  275. // A Recorder keeps a size limited record of log events.
  276. type Recorder struct {
  277. lines []Line
  278. initial int
  279. mut sync.Mutex
  280. }
  281. // A Line represents a single log entry.
  282. type Line struct {
  283. When time.Time
  284. Message string
  285. }
  286. func NewRecorder(l Logger, level LogLevel, size, initial int) *Recorder {
  287. r := &Recorder{
  288. lines: make([]Line, 0, size),
  289. initial: initial,
  290. }
  291. l.AddHandler(level, r.append)
  292. return r
  293. }
  294. func (r *Recorder) Since(t time.Time) []Line {
  295. r.mut.Lock()
  296. defer r.mut.Unlock()
  297. res := r.lines
  298. for i := 0; i < len(res) && res[i].When.Before(t); i++ {
  299. // nothing, just incrementing i
  300. }
  301. if len(res) == 0 {
  302. return nil
  303. }
  304. // We must copy the result as r.lines can be mutated as soon as the lock
  305. // is released.
  306. cp := make([]Line, len(res))
  307. copy(cp, res)
  308. return cp
  309. }
  310. func (r *Recorder) Clear() {
  311. r.mut.Lock()
  312. r.lines = r.lines[:0]
  313. r.mut.Unlock()
  314. }
  315. func (r *Recorder) append(l LogLevel, msg string) {
  316. line := Line{
  317. When: time.Now(),
  318. Message: msg,
  319. }
  320. r.mut.Lock()
  321. defer r.mut.Unlock()
  322. if len(r.lines) == cap(r.lines) {
  323. if r.initial > 0 {
  324. // Shift all lines one step to the left, keeping the "initial" first intact.
  325. copy(r.lines[r.initial+1:], r.lines[r.initial+2:])
  326. } else {
  327. copy(r.lines, r.lines[1:])
  328. }
  329. // Add the new one at the end
  330. r.lines[len(r.lines)-1] = line
  331. return
  332. }
  333. r.lines = append(r.lines, line)
  334. if len(r.lines) == r.initial {
  335. r.lines = append(r.lines, Line{time.Now(), "..."})
  336. }
  337. }