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