log.go 6.3 KB

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