logger.go 8.8 KB

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