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.

158 lines
4.8 KiB

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