本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
5.4KB

  1. // Copyright © 2016 Steve Francia <spf@spf13.com>.
  2. //
  3. // Use of this source code is governed by an MIT-style
  4. // license that can be found in the LICENSE file.
  5. package jwalterweatherman
  6. import (
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "log"
  11. )
  12. type Threshold int
  13. func (t Threshold) String() string {
  14. return prefixes[t]
  15. }
  16. const (
  17. LevelTrace Threshold = iota
  18. LevelDebug
  19. LevelInfo
  20. LevelWarn
  21. LevelError
  22. LevelCritical
  23. LevelFatal
  24. )
  25. var prefixes map[Threshold]string = map[Threshold]string{
  26. LevelTrace: "TRACE",
  27. LevelDebug: "DEBUG",
  28. LevelInfo: "INFO",
  29. LevelWarn: "WARN",
  30. LevelError: "ERROR",
  31. LevelCritical: "CRITICAL",
  32. LevelFatal: "FATAL",
  33. }
  34. // Notepad is where you leave a note!
  35. type Notepad struct {
  36. TRACE *log.Logger
  37. DEBUG *log.Logger
  38. INFO *log.Logger
  39. WARN *log.Logger
  40. ERROR *log.Logger
  41. CRITICAL *log.Logger
  42. FATAL *log.Logger
  43. LOG *log.Logger
  44. FEEDBACK *Feedback
  45. loggers [7]**log.Logger
  46. logHandle io.Writer
  47. outHandle io.Writer
  48. logThreshold Threshold
  49. stdoutThreshold Threshold
  50. prefix string
  51. flags int
  52. logListeners []LogListener
  53. }
  54. // A LogListener can ble supplied to a Notepad to listen on log writes for a given
  55. // threshold. This can be used to capture log events in unit tests and similar.
  56. // Note that this function will be invoked once for each log threshold. If
  57. // the given threshold is not of interest to you, return nil.
  58. // Note that these listeners will receive log events for a given threshold, even
  59. // if the current configuration says not to log it. That way you can count ERRORs even
  60. // if you don't print them to the console.
  61. type LogListener func(t Threshold) io.Writer
  62. // NewNotepad creates a new Notepad.
  63. func NewNotepad(
  64. outThreshold Threshold,
  65. logThreshold Threshold,
  66. outHandle, logHandle io.Writer,
  67. prefix string, flags int,
  68. logListeners ...LogListener,
  69. ) *Notepad {
  70. n := &Notepad{logListeners: logListeners}
  71. n.loggers = [7]**log.Logger{&n.TRACE, &n.DEBUG, &n.INFO, &n.WARN, &n.ERROR, &n.CRITICAL, &n.FATAL}
  72. n.outHandle = outHandle
  73. n.logHandle = logHandle
  74. n.stdoutThreshold = outThreshold
  75. n.logThreshold = logThreshold
  76. if len(prefix) != 0 {
  77. n.prefix = "[" + prefix + "] "
  78. } else {
  79. n.prefix = ""
  80. }
  81. n.flags = flags
  82. n.LOG = log.New(n.logHandle,
  83. "LOG: ",
  84. n.flags)
  85. n.FEEDBACK = &Feedback{out: log.New(outHandle, "", 0), log: n.LOG}
  86. n.init()
  87. return n
  88. }
  89. // init creates the loggers for each level depending on the notepad thresholds.
  90. func (n *Notepad) init() {
  91. logAndOut := io.MultiWriter(n.outHandle, n.logHandle)
  92. for t, logger := range n.loggers {
  93. threshold := Threshold(t)
  94. prefix := n.prefix + threshold.String() + " "
  95. switch {
  96. case threshold >= n.logThreshold && threshold >= n.stdoutThreshold:
  97. *logger = log.New(n.createLogWriters(threshold, logAndOut), prefix, n.flags)
  98. case threshold >= n.logThreshold:
  99. *logger = log.New(n.createLogWriters(threshold, n.logHandle), prefix, n.flags)
  100. case threshold >= n.stdoutThreshold:
  101. *logger = log.New(n.createLogWriters(threshold, n.outHandle), prefix, n.flags)
  102. default:
  103. *logger = log.New(n.createLogWriters(threshold, ioutil.Discard), prefix, n.flags)
  104. }
  105. }
  106. }
  107. func (n *Notepad) createLogWriters(t Threshold, handle io.Writer) io.Writer {
  108. if len(n.logListeners) == 0 {
  109. return handle
  110. }
  111. writers := []io.Writer{handle}
  112. for _, l := range n.logListeners {
  113. w := l(t)
  114. if w != nil {
  115. writers = append(writers, w)
  116. }
  117. }
  118. if len(writers) == 1 {
  119. return handle
  120. }
  121. return io.MultiWriter(writers...)
  122. }
  123. // SetLogThreshold changes the threshold above which messages are written to the
  124. // log file.
  125. func (n *Notepad) SetLogThreshold(threshold Threshold) {
  126. n.logThreshold = threshold
  127. n.init()
  128. }
  129. // SetLogOutput changes the file where log messages are written.
  130. func (n *Notepad) SetLogOutput(handle io.Writer) {
  131. n.logHandle = handle
  132. n.init()
  133. }
  134. // GetStdoutThreshold returns the defined Treshold for the log logger.
  135. func (n *Notepad) GetLogThreshold() Threshold {
  136. return n.logThreshold
  137. }
  138. // SetStdoutThreshold changes the threshold above which messages are written to the
  139. // standard output.
  140. func (n *Notepad) SetStdoutThreshold(threshold Threshold) {
  141. n.stdoutThreshold = threshold
  142. n.init()
  143. }
  144. // GetStdoutThreshold returns the Treshold for the stdout logger.
  145. func (n *Notepad) GetStdoutThreshold() Threshold {
  146. return n.stdoutThreshold
  147. }
  148. // SetPrefix changes the prefix used by the notepad. Prefixes are displayed between
  149. // brackets at the beginning of the line. An empty prefix won't be displayed at all.
  150. func (n *Notepad) SetPrefix(prefix string) {
  151. if len(prefix) != 0 {
  152. n.prefix = "[" + prefix + "] "
  153. } else {
  154. n.prefix = ""
  155. }
  156. n.init()
  157. }
  158. // SetFlags choose which flags the logger will display (after prefix and message
  159. // level). See the package log for more informations on this.
  160. func (n *Notepad) SetFlags(flags int) {
  161. n.flags = flags
  162. n.init()
  163. }
  164. // Feedback writes plainly to the outHandle while
  165. // logging with the standard extra information (date, file, etc).
  166. type Feedback struct {
  167. out *log.Logger
  168. log *log.Logger
  169. }
  170. func (fb *Feedback) Println(v ...interface{}) {
  171. fb.output(fmt.Sprintln(v...))
  172. }
  173. func (fb *Feedback) Printf(format string, v ...interface{}) {
  174. fb.output(fmt.Sprintf(format, v...))
  175. }
  176. func (fb *Feedback) Print(v ...interface{}) {
  177. fb.output(fmt.Sprint(v...))
  178. }
  179. func (fb *Feedback) output(s string) {
  180. if fb.out != nil {
  181. fb.out.Output(2, s)
  182. }
  183. if fb.log != nil {
  184. fb.log.Output(2, s)
  185. }
  186. }
上海开阖软件有限公司 沪ICP备12045867号-1