field.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. package log
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. type fieldType int
  7. const (
  8. stringType fieldType = iota
  9. boolType
  10. intType
  11. int32Type
  12. uint32Type
  13. int64Type
  14. uint64Type
  15. float32Type
  16. float64Type
  17. errorType
  18. objectType
  19. lazyLoggerType
  20. noopType
  21. )
  22. // Field instances are constructed via LogBool, LogString, and so on.
  23. // Tracing implementations may then handle them via the Field.Marshal
  24. // method.
  25. //
  26. // "heavily influenced by" (i.e., partially stolen from)
  27. // https://github.com/uber-go/zap
  28. type Field struct {
  29. key string
  30. fieldType fieldType
  31. numericVal int64
  32. stringVal string
  33. interfaceVal interface{}
  34. }
  35. // String adds a string-valued key:value pair to a Span.LogFields() record
  36. func String(key, val string) Field {
  37. return Field{
  38. key: key,
  39. fieldType: stringType,
  40. stringVal: val,
  41. }
  42. }
  43. // Bool adds a bool-valued key:value pair to a Span.LogFields() record
  44. func Bool(key string, val bool) Field {
  45. var numericVal int64
  46. if val {
  47. numericVal = 1
  48. }
  49. return Field{
  50. key: key,
  51. fieldType: boolType,
  52. numericVal: numericVal,
  53. }
  54. }
  55. // Int adds an int-valued key:value pair to a Span.LogFields() record
  56. func Int(key string, val int) Field {
  57. return Field{
  58. key: key,
  59. fieldType: intType,
  60. numericVal: int64(val),
  61. }
  62. }
  63. // Int32 adds an int32-valued key:value pair to a Span.LogFields() record
  64. func Int32(key string, val int32) Field {
  65. return Field{
  66. key: key,
  67. fieldType: int32Type,
  68. numericVal: int64(val),
  69. }
  70. }
  71. // Int64 adds an int64-valued key:value pair to a Span.LogFields() record
  72. func Int64(key string, val int64) Field {
  73. return Field{
  74. key: key,
  75. fieldType: int64Type,
  76. numericVal: val,
  77. }
  78. }
  79. // Uint32 adds a uint32-valued key:value pair to a Span.LogFields() record
  80. func Uint32(key string, val uint32) Field {
  81. return Field{
  82. key: key,
  83. fieldType: uint32Type,
  84. numericVal: int64(val),
  85. }
  86. }
  87. // Uint64 adds a uint64-valued key:value pair to a Span.LogFields() record
  88. func Uint64(key string, val uint64) Field {
  89. return Field{
  90. key: key,
  91. fieldType: uint64Type,
  92. numericVal: int64(val),
  93. }
  94. }
  95. // Float32 adds a float32-valued key:value pair to a Span.LogFields() record
  96. func Float32(key string, val float32) Field {
  97. return Field{
  98. key: key,
  99. fieldType: float32Type,
  100. numericVal: int64(math.Float32bits(val)),
  101. }
  102. }
  103. // Float64 adds a float64-valued key:value pair to a Span.LogFields() record
  104. func Float64(key string, val float64) Field {
  105. return Field{
  106. key: key,
  107. fieldType: float64Type,
  108. numericVal: int64(math.Float64bits(val)),
  109. }
  110. }
  111. // Error adds an error with the key "error.object" to a Span.LogFields() record
  112. func Error(err error) Field {
  113. return Field{
  114. key: "error.object",
  115. fieldType: errorType,
  116. interfaceVal: err,
  117. }
  118. }
  119. // Object adds an object-valued key:value pair to a Span.LogFields() record
  120. // Please pass in an immutable object, otherwise there may be concurrency issues.
  121. // Such as passing in the map, log.Object may result in "fatal error: concurrent map iteration and map write".
  122. // Because span is sent asynchronously, it is possible that this map will also be modified.
  123. func Object(key string, obj interface{}) Field {
  124. return Field{
  125. key: key,
  126. fieldType: objectType,
  127. interfaceVal: obj,
  128. }
  129. }
  130. // Event creates a string-valued Field for span logs with key="event" and value=val.
  131. func Event(val string) Field {
  132. return String("event", val)
  133. }
  134. // Message creates a string-valued Field for span logs with key="message" and value=val.
  135. func Message(val string) Field {
  136. return String("message", val)
  137. }
  138. // LazyLogger allows for user-defined, late-bound logging of arbitrary data
  139. type LazyLogger func(fv Encoder)
  140. // Lazy adds a LazyLogger to a Span.LogFields() record; the tracing
  141. // implementation will call the LazyLogger function at an indefinite time in
  142. // the future (after Lazy() returns).
  143. func Lazy(ll LazyLogger) Field {
  144. return Field{
  145. fieldType: lazyLoggerType,
  146. interfaceVal: ll,
  147. }
  148. }
  149. // Noop creates a no-op log field that should be ignored by the tracer.
  150. // It can be used to capture optional fields, for example those that should
  151. // only be logged in non-production environment:
  152. //
  153. // func customerField(order *Order) log.Field {
  154. // if os.Getenv("ENVIRONMENT") == "dev" {
  155. // return log.String("customer", order.Customer.ID)
  156. // }
  157. // return log.Noop()
  158. // }
  159. //
  160. // span.LogFields(log.String("event", "purchase"), customerField(order))
  161. //
  162. func Noop() Field {
  163. return Field{
  164. fieldType: noopType,
  165. }
  166. }
  167. // Encoder allows access to the contents of a Field (via a call to
  168. // Field.Marshal).
  169. //
  170. // Tracer implementations typically provide an implementation of Encoder;
  171. // OpenTracing callers typically do not need to concern themselves with it.
  172. type Encoder interface {
  173. EmitString(key, value string)
  174. EmitBool(key string, value bool)
  175. EmitInt(key string, value int)
  176. EmitInt32(key string, value int32)
  177. EmitInt64(key string, value int64)
  178. EmitUint32(key string, value uint32)
  179. EmitUint64(key string, value uint64)
  180. EmitFloat32(key string, value float32)
  181. EmitFloat64(key string, value float64)
  182. EmitObject(key string, value interface{})
  183. EmitLazyLogger(value LazyLogger)
  184. }
  185. // Marshal passes a Field instance through to the appropriate
  186. // field-type-specific method of an Encoder.
  187. func (lf Field) Marshal(visitor Encoder) {
  188. switch lf.fieldType {
  189. case stringType:
  190. visitor.EmitString(lf.key, lf.stringVal)
  191. case boolType:
  192. visitor.EmitBool(lf.key, lf.numericVal != 0)
  193. case intType:
  194. visitor.EmitInt(lf.key, int(lf.numericVal))
  195. case int32Type:
  196. visitor.EmitInt32(lf.key, int32(lf.numericVal))
  197. case int64Type:
  198. visitor.EmitInt64(lf.key, int64(lf.numericVal))
  199. case uint32Type:
  200. visitor.EmitUint32(lf.key, uint32(lf.numericVal))
  201. case uint64Type:
  202. visitor.EmitUint64(lf.key, uint64(lf.numericVal))
  203. case float32Type:
  204. visitor.EmitFloat32(lf.key, math.Float32frombits(uint32(lf.numericVal)))
  205. case float64Type:
  206. visitor.EmitFloat64(lf.key, math.Float64frombits(uint64(lf.numericVal)))
  207. case errorType:
  208. if err, ok := lf.interfaceVal.(error); ok {
  209. visitor.EmitString(lf.key, err.Error())
  210. } else {
  211. visitor.EmitString(lf.key, "<nil>")
  212. }
  213. case objectType:
  214. visitor.EmitObject(lf.key, lf.interfaceVal)
  215. case lazyLoggerType:
  216. visitor.EmitLazyLogger(lf.interfaceVal.(LazyLogger))
  217. case noopType:
  218. // intentionally left blank
  219. }
  220. }
  221. // Key returns the field's key.
  222. func (lf Field) Key() string {
  223. return lf.key
  224. }
  225. // Value returns the field's value as interface{}.
  226. func (lf Field) Value() interface{} {
  227. switch lf.fieldType {
  228. case stringType:
  229. return lf.stringVal
  230. case boolType:
  231. return lf.numericVal != 0
  232. case intType:
  233. return int(lf.numericVal)
  234. case int32Type:
  235. return int32(lf.numericVal)
  236. case int64Type:
  237. return int64(lf.numericVal)
  238. case uint32Type:
  239. return uint32(lf.numericVal)
  240. case uint64Type:
  241. return uint64(lf.numericVal)
  242. case float32Type:
  243. return math.Float32frombits(uint32(lf.numericVal))
  244. case float64Type:
  245. return math.Float64frombits(uint64(lf.numericVal))
  246. case errorType, objectType, lazyLoggerType:
  247. return lf.interfaceVal
  248. case noopType:
  249. return nil
  250. default:
  251. return nil
  252. }
  253. }
  254. // String returns a string representation of the key and value.
  255. func (lf Field) String() string {
  256. return fmt.Sprint(lf.key, ":", lf.Value())
  257. }