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.

195 lines
5.8 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. package log
  2. import "fmt"
  3. type level byte
  4. const (
  5. levelDebug level = 1 << iota
  6. levelInfo
  7. levelError
  8. )
  9. type filter struct {
  10. next Logger
  11. allowed level // XOR'd levels for default case
  12. initiallyAllowed level // XOR'd levels for initial case
  13. allowedKeyvals map[keyval]level // When key-value match, use this level
  14. }
  15. type keyval struct {
  16. key interface{}
  17. value interface{}
  18. }
  19. // NewFilter wraps next and implements filtering. See the commentary on the
  20. // Option functions for a detailed description of how to configure levels. If
  21. // no options are provided, all leveled log events created with Debug, Info or
  22. // Error helper methods are squelched.
  23. func NewFilter(next Logger, options ...Option) Logger {
  24. l := &filter{
  25. next: next,
  26. allowedKeyvals: make(map[keyval]level),
  27. }
  28. for _, option := range options {
  29. option(l)
  30. }
  31. l.initiallyAllowed = l.allowed
  32. return l
  33. }
  34. func (l *filter) Info(msg string, keyvals ...interface{}) {
  35. levelAllowed := l.allowed&levelInfo != 0
  36. if !levelAllowed {
  37. return
  38. }
  39. l.next.Info(msg, keyvals...)
  40. }
  41. func (l *filter) Debug(msg string, keyvals ...interface{}) {
  42. levelAllowed := l.allowed&levelDebug != 0
  43. if !levelAllowed {
  44. return
  45. }
  46. l.next.Debug(msg, keyvals...)
  47. }
  48. func (l *filter) Error(msg string, keyvals ...interface{}) {
  49. levelAllowed := l.allowed&levelError != 0
  50. if !levelAllowed {
  51. return
  52. }
  53. l.next.Error(msg, keyvals...)
  54. }
  55. // With implements Logger by constructing a new filter with a keyvals appended
  56. // to the logger.
  57. //
  58. // If custom level was set for a keyval pair using one of the
  59. // Allow*With methods, it is used as the logger's level.
  60. //
  61. // Examples:
  62. // logger = log.NewFilter(logger, log.AllowError(), log.AllowInfoWith("module", "crypto"))
  63. // logger.With("module", "crypto").Info("Hello") # produces "I... Hello module=crypto"
  64. //
  65. // logger = log.NewFilter(logger, log.AllowError(),
  66. // log.AllowInfoWith("module", "crypto"),
  67. // log.AllowNoneWith("user", "Sam"))
  68. // logger.With("module", "crypto", "user", "Sam").Info("Hello") # returns nil
  69. //
  70. // logger = log.NewFilter(logger,
  71. // log.AllowError(),
  72. // log.AllowInfoWith("module", "crypto"), log.AllowNoneWith("user", "Sam"))
  73. // logger.With("user", "Sam").With("module", "crypto").Info("Hello") # produces "I... Hello module=crypto user=Sam"
  74. func (l *filter) With(keyvals ...interface{}) Logger {
  75. keyInAllowedKeyvals := false
  76. for i := len(keyvals) - 2; i >= 0; i -= 2 {
  77. for kv, allowed := range l.allowedKeyvals {
  78. if keyvals[i] == kv.key {
  79. keyInAllowedKeyvals = true
  80. // Example:
  81. // logger = log.NewFilter(logger, log.AllowError(), log.AllowInfoWith("module", "crypto"))
  82. // logger.With("module", "crypto")
  83. if keyvals[i+1] == kv.value {
  84. return &filter{
  85. next: l.next.With(keyvals...),
  86. allowed: allowed, // set the desired level
  87. allowedKeyvals: l.allowedKeyvals,
  88. initiallyAllowed: l.initiallyAllowed,
  89. }
  90. }
  91. }
  92. }
  93. }
  94. // Example:
  95. // logger = log.NewFilter(logger, log.AllowError(), log.AllowInfoWith("module", "crypto"))
  96. // logger.With("module", "main")
  97. if keyInAllowedKeyvals {
  98. return &filter{
  99. next: l.next.With(keyvals...),
  100. allowed: l.initiallyAllowed, // return back to initially allowed
  101. allowedKeyvals: l.allowedKeyvals,
  102. initiallyAllowed: l.initiallyAllowed,
  103. }
  104. }
  105. return &filter{
  106. next: l.next.With(keyvals...),
  107. allowed: l.allowed, // simply continue with the current level
  108. allowedKeyvals: l.allowedKeyvals,
  109. initiallyAllowed: l.initiallyAllowed,
  110. }
  111. }
  112. //--------------------------------------------------------------------------------
  113. // Option sets a parameter for the filter.
  114. type Option func(*filter)
  115. // AllowLevel returns an option for the given level or error if no option exist
  116. // for such level.
  117. func AllowLevel(lvl string) (Option, error) {
  118. switch lvl {
  119. case "debug":
  120. return AllowDebug(), nil
  121. case "info":
  122. return AllowInfo(), nil
  123. case "error":
  124. return AllowError(), nil
  125. case "none":
  126. return AllowNone(), nil
  127. default:
  128. return nil, fmt.Errorf("expected either \"info\", \"debug\", \"error\" or \"none\" level, given %s", lvl)
  129. }
  130. }
  131. // AllowAll is an alias for AllowDebug.
  132. func AllowAll() Option {
  133. return AllowDebug()
  134. }
  135. // AllowDebug allows error, info and debug level log events to pass.
  136. func AllowDebug() Option {
  137. return allowed(levelError | levelInfo | levelDebug)
  138. }
  139. // AllowInfo allows error and info level log events to pass.
  140. func AllowInfo() Option {
  141. return allowed(levelError | levelInfo)
  142. }
  143. // AllowError allows only error level log events to pass.
  144. func AllowError() Option {
  145. return allowed(levelError)
  146. }
  147. // AllowNone allows no leveled log events to pass.
  148. func AllowNone() Option {
  149. return allowed(0)
  150. }
  151. func allowed(allowed level) Option {
  152. return func(l *filter) { l.allowed = allowed }
  153. }
  154. // AllowDebugWith allows error, info and debug level log events to pass for a specific key value pair.
  155. func AllowDebugWith(key interface{}, value interface{}) Option {
  156. return func(l *filter) { l.allowedKeyvals[keyval{key, value}] = levelError | levelInfo | levelDebug }
  157. }
  158. // AllowInfoWith allows error and info level log events to pass for a specific key value pair.
  159. func AllowInfoWith(key interface{}, value interface{}) Option {
  160. return func(l *filter) { l.allowedKeyvals[keyval{key, value}] = levelError | levelInfo }
  161. }
  162. // AllowErrorWith allows only error level log events to pass for a specific key value pair.
  163. func AllowErrorWith(key interface{}, value interface{}) Option {
  164. return func(l *filter) { l.allowedKeyvals[keyval{key, value}] = levelError }
  165. }
  166. // AllowNoneWith allows no leveled log events to pass for a specific key value pair.
  167. func AllowNoneWith(key interface{}, value interface{}) Option {
  168. return func(l *filter) { l.allowedKeyvals[keyval{key, value}] = 0 }
  169. }