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