2
0

log.go 4.8 KB

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