1
0

logger.go 9.2 KB

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