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