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
14 // ErrMissingValue is appended to keyvals slices with odd length to substitute
16 var ErrMissingValue = errors.New("(MISSING)")
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.
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 {
28 l := newContext(logger)
29 kvs := append(l.keyvals, keyvals...)
31 kvs = append(kvs, ErrMissingValue)
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),
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.
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 {
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 {
63 kvs := make([]interface{}, 0, n)
64 kvs = append(kvs, keyvals...)
66 kvs = append(kvs, ErrMissingValue)
68 kvs = append(kvs, l.keyvals...)
72 hasValuer: l.hasValuer || containsValuer(keyvals),
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
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.
88 // Two implementation details provide the needed stack depth consistency.
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.
101 func newContext(logger Logger) *context {
102 if c, ok := logger.(*context); ok {
105 return &context{logger: logger}
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...)
114 kvs = append(kvs, ErrMissingValue)
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...)
122 bindValues(kvs[:len(l.keyvals)])
124 return l.logger.Log(kvs...)
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
132 // Log implements Logger by calling f(keyvals...).
133 func (f LoggerFunc) Log(keyvals ...interface{}) error {