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.

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