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