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