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.

191 lines
5.7 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 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(), log.AllowInfoWith("module", "crypto"), log.AllowNoneWith("user", "Sam"))
  66. // logger.With("module", "crypto", "user", "Sam").Info("Hello") # returns nil
  67. //
  68. // logger = log.NewFilter(logger, log.AllowError(), log.AllowInfoWith("module", "crypto"), log.AllowNoneWith("user", "Sam"))
  69. // logger.With("user", "Sam").With("module", "crypto").Info("Hello") # produces "I... Hello module=crypto user=Sam"
  70. func (l *filter) With(keyvals ...interface{}) Logger {
  71. keyInAllowedKeyvals := false
  72. for i := len(keyvals) - 2; i >= 0; i -= 2 {
  73. for kv, allowed := range l.allowedKeyvals {
  74. if keyvals[i] == kv.key {
  75. keyInAllowedKeyvals = true
  76. // Example:
  77. // logger = log.NewFilter(logger, log.AllowError(), log.AllowInfoWith("module", "crypto"))
  78. // logger.With("module", "crypto")
  79. if keyvals[i+1] == kv.value {
  80. return &filter{
  81. next: l.next.With(keyvals...),
  82. allowed: allowed, // set the desired level
  83. allowedKeyvals: l.allowedKeyvals,
  84. initiallyAllowed: l.initiallyAllowed,
  85. }
  86. }
  87. }
  88. }
  89. }
  90. // Example:
  91. // logger = log.NewFilter(logger, log.AllowError(), log.AllowInfoWith("module", "crypto"))
  92. // logger.With("module", "main")
  93. if keyInAllowedKeyvals {
  94. return &filter{
  95. next: l.next.With(keyvals...),
  96. allowed: l.initiallyAllowed, // return back to initially allowed
  97. allowedKeyvals: l.allowedKeyvals,
  98. initiallyAllowed: l.initiallyAllowed,
  99. }
  100. }
  101. return &filter{
  102. next: l.next.With(keyvals...),
  103. allowed: l.allowed, // simply continue with the current level
  104. allowedKeyvals: l.allowedKeyvals,
  105. initiallyAllowed: l.initiallyAllowed,
  106. }
  107. }
  108. //--------------------------------------------------------------------------------
  109. // Option sets a parameter for the filter.
  110. type Option func(*filter)
  111. // AllowLevel returns an option for the given level or error if no option exist
  112. // for such level.
  113. func AllowLevel(lvl string) (Option, error) {
  114. switch lvl {
  115. case "debug":
  116. return AllowDebug(), nil
  117. case "info":
  118. return AllowInfo(), nil
  119. case "error":
  120. return AllowError(), nil
  121. case "none":
  122. return AllowNone(), nil
  123. default:
  124. return nil, fmt.Errorf("Expected either \"info\", \"debug\", \"error\" or \"none\" level, given %s", lvl)
  125. }
  126. }
  127. // AllowAll is an alias for AllowDebug.
  128. func AllowAll() Option {
  129. return AllowDebug()
  130. }
  131. // AllowDebug allows error, info and debug level log events to pass.
  132. func AllowDebug() Option {
  133. return allowed(levelError | levelInfo | levelDebug)
  134. }
  135. // AllowInfo allows error and info level log events to pass.
  136. func AllowInfo() Option {
  137. return allowed(levelError | levelInfo)
  138. }
  139. // AllowError allows only error level log events to pass.
  140. func AllowError() Option {
  141. return allowed(levelError)
  142. }
  143. // AllowNone allows no leveled log events to pass.
  144. func AllowNone() Option {
  145. return allowed(0)
  146. }
  147. func allowed(allowed level) Option {
  148. return func(l *filter) { l.allowed = allowed }
  149. }
  150. // AllowDebugWith allows error, info and debug level log events to pass for a specific key value pair.
  151. func AllowDebugWith(key interface{}, value interface{}) Option {
  152. return func(l *filter) { l.allowedKeyvals[keyval{key, value}] = levelError | levelInfo | levelDebug }
  153. }
  154. // AllowInfoWith allows error and info level log events to pass for a specific key value pair.
  155. func AllowInfoWith(key interface{}, value interface{}) Option {
  156. return func(l *filter) { l.allowedKeyvals[keyval{key, value}] = levelError | levelInfo }
  157. }
  158. // AllowErrorWith allows only error level log events to pass for a specific key value pair.
  159. func AllowErrorWith(key interface{}, value interface{}) Option {
  160. return func(l *filter) { l.allowedKeyvals[keyval{key, value}] = levelError }
  161. }
  162. // AllowNoneWith allows no leveled log events to pass for a specific key value pair.
  163. func AllowNoneWith(key interface{}, value interface{}) Option {
  164. return func(l *filter) { l.allowedKeyvals[keyval{key, value}] = 0 }
  165. }