...

Source file src/github.com/go-kit/log/log.go

Documentation: github.com/go-kit/log

     1  package log
     2  
     3  import "errors"
     4  
     5  // Logger is the fundamental interface for all log operations. Log creates a
     6  // log event from keyvals, a variadic sequence of alternating keys and values.
     7  // Implementations must be safe for concurrent use by multiple goroutines. In
     8  // particular, any implementation of Logger that appends to keyvals or
     9  // modifies or retains any of its elements must make a copy first.
    10  type Logger interface {
    11  	Log(keyvals ...interface{}) error
    12  }
    13  
    14  // ErrMissingValue is appended to keyvals slices with odd length to substitute
    15  // the missing value.
    16  var ErrMissingValue = errors.New("(MISSING)")
    17  
    18  // With returns a new contextual logger with keyvals prepended to those passed
    19  // to calls to Log. If logger is also a contextual logger created by With,
    20  // WithPrefix, or WithSuffix, keyvals is appended to the existing context.
    21  //
    22  // The returned Logger replaces all value elements (odd indexes) containing a
    23  // Valuer with their generated value for each call to its Log method.
    24  func With(logger Logger, keyvals ...interface{}) Logger {
    25  	if len(keyvals) == 0 {
    26  		return logger
    27  	}
    28  	l := newContext(logger)
    29  	kvs := append(l.keyvals, keyvals...)
    30  	if len(kvs)%2 != 0 {
    31  		kvs = append(kvs, ErrMissingValue)
    32  	}
    33  	return &context{
    34  		logger: l.logger,
    35  		// Limiting the capacity of the stored keyvals ensures that a new
    36  		// backing array is created if the slice must grow in Log or With.
    37  		// Using the extra capacity without copying risks a data race that
    38  		// would violate the Logger interface contract.
    39  		keyvals:    kvs[:len(kvs):len(kvs)],
    40  		hasValuer:  l.hasValuer || containsValuer(keyvals),
    41  		sKeyvals:   l.sKeyvals,
    42  		sHasValuer: l.sHasValuer,
    43  	}
    44  }
    45  
    46  // WithPrefix returns a new contextual logger with keyvals prepended to those
    47  // passed to calls to Log. If logger is also a contextual logger created by
    48  // With, WithPrefix, or WithSuffix, keyvals is prepended to the existing context.
    49  //
    50  // The returned Logger replaces all value elements (odd indexes) containing a
    51  // Valuer with their generated value for each call to its Log method.
    52  func WithPrefix(logger Logger, keyvals ...interface{}) Logger {
    53  	if len(keyvals) == 0 {
    54  		return logger
    55  	}
    56  	l := newContext(logger)
    57  	// Limiting the capacity of the stored keyvals ensures that a new
    58  	// backing array is created if the slice must grow in Log or With.
    59  	// Using the extra capacity without copying risks a data race that
    60  	// would violate the Logger interface contract.
    61  	n := len(l.keyvals) + len(keyvals)
    62  	if len(keyvals)%2 != 0 {
    63  		n++
    64  	}
    65  	kvs := make([]interface{}, 0, n)
    66  	kvs = append(kvs, keyvals...)
    67  	if len(kvs)%2 != 0 {
    68  		kvs = append(kvs, ErrMissingValue)
    69  	}
    70  	kvs = append(kvs, l.keyvals...)
    71  	return &context{
    72  		logger:     l.logger,
    73  		keyvals:    kvs,
    74  		hasValuer:  l.hasValuer || containsValuer(keyvals),
    75  		sKeyvals:   l.sKeyvals,
    76  		sHasValuer: l.sHasValuer,
    77  	}
    78  }
    79  
    80  // WithSuffix returns a new contextual logger with keyvals appended to those
    81  // passed to calls to Log. If logger is also a contextual logger created by
    82  // With, WithPrefix, or WithSuffix, keyvals is appended to the existing context.
    83  //
    84  // The returned Logger replaces all value elements (odd indexes) containing a
    85  // Valuer with their generated value for each call to its Log method.
    86  func WithSuffix(logger Logger, keyvals ...interface{}) Logger {
    87  	if len(keyvals) == 0 {
    88  		return logger
    89  	}
    90  	l := newContext(logger)
    91  	// Limiting the capacity of the stored keyvals ensures that a new
    92  	// backing array is created if the slice must grow in Log or With.
    93  	// Using the extra capacity without copying risks a data race that
    94  	// would violate the Logger interface contract.
    95  	n := len(l.sKeyvals) + len(keyvals)
    96  	if len(keyvals)%2 != 0 {
    97  		n++
    98  	}
    99  	kvs := make([]interface{}, 0, n)
   100  	kvs = append(kvs, keyvals...)
   101  	if len(kvs)%2 != 0 {
   102  		kvs = append(kvs, ErrMissingValue)
   103  	}
   104  	kvs = append(l.sKeyvals, kvs...)
   105  	return &context{
   106  		logger:     l.logger,
   107  		keyvals:    l.keyvals,
   108  		hasValuer:  l.hasValuer,
   109  		sKeyvals:   kvs,
   110  		sHasValuer: l.sHasValuer || containsValuer(keyvals),
   111  	}
   112  }
   113  
   114  // context is the Logger implementation returned by With, WithPrefix, and
   115  // WithSuffix. It wraps a Logger and holds keyvals that it includes in all
   116  // log events. Its Log method calls bindValues to generate values for each
   117  // Valuer in the context keyvals.
   118  //
   119  // A context must always have the same number of stack frames between calls to
   120  // its Log method and the eventual binding of Valuers to their value. This
   121  // requirement comes from the functional requirement to allow a context to
   122  // resolve application call site information for a Caller stored in the
   123  // context. To do this we must be able to predict the number of logging
   124  // functions on the stack when bindValues is called.
   125  //
   126  // Two implementation details provide the needed stack depth consistency.
   127  //
   128  //    1. newContext avoids introducing an additional layer when asked to
   129  //       wrap another context.
   130  //    2. With, WithPrefix, and WithSuffix avoid introducing an additional
   131  //       layer by returning a newly constructed context with a merged keyvals
   132  //       rather than simply wrapping the existing context.
   133  type context struct {
   134  	logger     Logger
   135  	keyvals    []interface{}
   136  	sKeyvals   []interface{} // suffixes
   137  	hasValuer  bool
   138  	sHasValuer bool
   139  }
   140  
   141  func newContext(logger Logger) *context {
   142  	if c, ok := logger.(*context); ok {
   143  		return c
   144  	}
   145  	return &context{logger: logger}
   146  }
   147  
   148  // Log replaces all value elements (odd indexes) containing a Valuer in the
   149  // stored context with their generated value, appends keyvals, and passes the
   150  // result to the wrapped Logger.
   151  func (l *context) Log(keyvals ...interface{}) error {
   152  	kvs := append(l.keyvals, keyvals...)
   153  	if len(kvs)%2 != 0 {
   154  		kvs = append(kvs, ErrMissingValue)
   155  	}
   156  	if l.hasValuer {
   157  		// If no keyvals were appended above then we must copy l.keyvals so
   158  		// that future log events will reevaluate the stored Valuers.
   159  		if len(keyvals) == 0 {
   160  			kvs = append([]interface{}{}, l.keyvals...)
   161  		}
   162  		bindValues(kvs[:(len(l.keyvals))])
   163  	}
   164  	kvs = append(kvs, l.sKeyvals...)
   165  	if l.sHasValuer {
   166  		bindValues(kvs[len(kvs)-len(l.sKeyvals):])
   167  	}
   168  	return l.logger.Log(kvs...)
   169  }
   170  
   171  // LoggerFunc is an adapter to allow use of ordinary functions as Loggers. If
   172  // f is a function with the appropriate signature, LoggerFunc(f) is a Logger
   173  // object that calls f.
   174  type LoggerFunc func(...interface{}) error
   175  
   176  // Log implements Logger by calling f(keyvals...).
   177  func (f LoggerFunc) Log(keyvals ...interface{}) error {
   178  	return f(keyvals...)
   179  }
   180  

View as plain text