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  }