github.com/DFWallet/tendermint-cosmos@v0.0.2/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  }