github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/go-kit/kit/log/log.go (about) 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 or 20 // WithPrefix, 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 } 42 } 43 44 // WithPrefix returns a new contextual logger with keyvals prepended to those 45 // passed to calls to Log. If logger is also a contextual logger created by 46 // With or WithPrefix, keyvals is prepended to the existing context. 47 // 48 // The returned Logger replaces all value elements (odd indexes) containing a 49 // Valuer with their generated value for each call to its Log method. 50 func WithPrefix(logger Logger, keyvals ...interface{}) Logger { 51 if len(keyvals) == 0 { 52 return logger 53 } 54 l := newContext(logger) 55 // Limiting the capacity of the stored keyvals ensures that a new 56 // backing array is created if the slice must grow in Log or With. 57 // Using the extra capacity without copying risks a data race that 58 // would violate the Logger interface contract. 59 n := len(l.keyvals) + len(keyvals) 60 if len(keyvals)%2 != 0 { 61 n++ 62 } 63 kvs := make([]interface{}, 0, n) 64 kvs = append(kvs, keyvals...) 65 if len(kvs)%2 != 0 { 66 kvs = append(kvs, ErrMissingValue) 67 } 68 kvs = append(kvs, l.keyvals...) 69 return &context{ 70 logger: l.logger, 71 keyvals: kvs, 72 hasValuer: l.hasValuer || containsValuer(keyvals), 73 } 74 } 75 76 // context is the Logger implementation returned by With and WithPrefix. It 77 // wraps a Logger and holds keyvals that it includes in all log events. Its 78 // Log method calls bindValues to generate values for each Valuer in the 79 // context keyvals. 80 // 81 // A context must always have the same number of stack frames between calls to 82 // its Log method and the eventual binding of Valuers to their value. This 83 // requirement comes from the functional requirement to allow a context to 84 // resolve application call site information for a Caller stored in the 85 // context. To do this we must be able to predict the number of logging 86 // functions on the stack when bindValues is called. 87 // 88 // Two implementation details provide the needed stack depth consistency. 89 // 90 // 1. newContext avoids introducing an additional layer when asked to 91 // wrap another context. 92 // 2. With and WithPrefix avoid introducing an additional layer by 93 // returning a newly constructed context with a merged keyvals rather 94 // than simply wrapping the existing context. 95 type context struct { 96 logger Logger 97 keyvals []interface{} 98 hasValuer bool 99 } 100 101 func newContext(logger Logger) *context { 102 if c, ok := logger.(*context); ok { 103 return c 104 } 105 return &context{logger: logger} 106 } 107 108 // Log replaces all value elements (odd indexes) containing a Valuer in the 109 // stored context with their generated value, appends keyvals, and passes the 110 // result to the wrapped Logger. 111 func (l *context) Log(keyvals ...interface{}) error { 112 kvs := append(l.keyvals, keyvals...) 113 if len(kvs)%2 != 0 { 114 kvs = append(kvs, ErrMissingValue) 115 } 116 if l.hasValuer { 117 // If no keyvals were appended above then we must copy l.keyvals so 118 // that future log events will reevaluate the stored Valuers. 119 if len(keyvals) == 0 { 120 kvs = append([]interface{}{}, l.keyvals...) 121 } 122 bindValues(kvs[:len(l.keyvals)]) 123 } 124 return l.logger.Log(kvs...) 125 } 126 127 // LoggerFunc is an adapter to allow use of ordinary functions as Loggers. If 128 // f is a function with the appropriate signature, LoggerFunc(f) is a Logger 129 // object that calls f. 130 type LoggerFunc func(...interface{}) error 131 132 // Log implements Logger by calling f(keyvals...). 133 func (f LoggerFunc) Log(keyvals ...interface{}) error { 134 return f(keyvals...) 135 }