logger.go 8.9 KB

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