value.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. package log
  2. import (
  3. "runtime"
  4. "strconv"
  5. "strings"
  6. "time"
  7. )
  8. // A Valuer generates a log value. When passed to With or WithPrefix in a
  9. // value element (odd indexes), it represents a dynamic value which is re-
  10. // evaluated with each log event.
  11. type Valuer func() interface{}
  12. // bindValues replaces all value elements (odd indexes) containing a Valuer
  13. // with their generated value.
  14. func bindValues(keyvals []interface{}) {
  15. for i := 1; i < len(keyvals); i += 2 {
  16. if v, ok := keyvals[i].(Valuer); ok {
  17. keyvals[i] = v()
  18. }
  19. }
  20. }
  21. // containsValuer returns true if any of the value elements (odd indexes)
  22. // contain a Valuer.
  23. func containsValuer(keyvals []interface{}) bool {
  24. for i := 1; i < len(keyvals); i += 2 {
  25. if _, ok := keyvals[i].(Valuer); ok {
  26. return true
  27. }
  28. }
  29. return false
  30. }
  31. // Timestamp returns a timestamp Valuer. It invokes the t function to get the
  32. // time; unless you are doing something tricky, pass time.Now.
  33. //
  34. // Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
  35. // are TimestampFormats that use the RFC3339Nano format.
  36. func Timestamp(t func() time.Time) Valuer {
  37. return func() interface{} { return t() }
  38. }
  39. // TimestampFormat returns a timestamp Valuer with a custom time format. It
  40. // invokes the t function to get the time to format; unless you are doing
  41. // something tricky, pass time.Now. The layout string is passed to
  42. // Time.Format.
  43. //
  44. // Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
  45. // are TimestampFormats that use the RFC3339Nano format.
  46. func TimestampFormat(t func() time.Time, layout string) Valuer {
  47. return func() interface{} {
  48. return timeFormat{
  49. time: t(),
  50. layout: layout,
  51. }
  52. }
  53. }
  54. // A timeFormat represents an instant in time and a layout used when
  55. // marshaling to a text format.
  56. type timeFormat struct {
  57. time time.Time
  58. layout string
  59. }
  60. func (tf timeFormat) String() string {
  61. return tf.time.Format(tf.layout)
  62. }
  63. // MarshalText implements encoding.TextMarshaller.
  64. func (tf timeFormat) MarshalText() (text []byte, err error) {
  65. // The following code adapted from the standard library time.Time.Format
  66. // method. Using the same undocumented magic constant to extend the size
  67. // of the buffer as seen there.
  68. b := make([]byte, 0, len(tf.layout)+10)
  69. b = tf.time.AppendFormat(b, tf.layout)
  70. return b, nil
  71. }
  72. // Caller returns a Valuer that returns a file and line from a specified depth
  73. // in the callstack. Users will probably want to use DefaultCaller.
  74. func Caller(depth int) Valuer {
  75. return func() interface{} {
  76. _, file, line, _ := runtime.Caller(depth)
  77. idx := strings.LastIndexByte(file, '/')
  78. // using idx+1 below handles both of following cases:
  79. // idx == -1 because no "/" was found, or
  80. // idx >= 0 and we want to start at the character after the found "/".
  81. return file[idx+1:] + ":" + strconv.Itoa(line)
  82. }
  83. }
  84. var (
  85. // DefaultTimestamp is a Valuer that returns the current wallclock time,
  86. // respecting time zones, when bound.
  87. DefaultTimestamp = TimestampFormat(time.Now, time.RFC3339Nano)
  88. // DefaultTimestampUTC is a Valuer that returns the current time in UTC
  89. // when bound.
  90. DefaultTimestampUTC = TimestampFormat(
  91. func() time.Time { return time.Now().UTC() },
  92. time.RFC3339Nano,
  93. )
  94. // DefaultCaller is a Valuer that returns the file and line where the Log
  95. // method was invoked. It can only be used with log.With.
  96. DefaultCaller = Caller(3)
  97. )