field.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Copyright (c) 2016 Uber Technologies, Inc.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. package zapcore
  21. import (
  22. "bytes"
  23. "fmt"
  24. "math"
  25. "reflect"
  26. "time"
  27. )
  28. // A FieldType indicates which member of the Field union struct should be used
  29. // and how it should be serialized.
  30. type FieldType uint8
  31. const (
  32. // UnknownType is the default field type. Attempting to add it to an encoder will panic.
  33. UnknownType FieldType = iota
  34. // ArrayMarshalerType indicates that the field carries an ArrayMarshaler.
  35. ArrayMarshalerType
  36. // ObjectMarshalerType indicates that the field carries an ObjectMarshaler.
  37. ObjectMarshalerType
  38. // BinaryType indicates that the field carries an opaque binary blob.
  39. BinaryType
  40. // BoolType indicates that the field carries a bool.
  41. BoolType
  42. // ByteStringType indicates that the field carries UTF-8 encoded bytes.
  43. ByteStringType
  44. // Complex128Type indicates that the field carries a complex128.
  45. Complex128Type
  46. // Complex64Type indicates that the field carries a complex128.
  47. Complex64Type
  48. // DurationType indicates that the field carries a time.Duration.
  49. DurationType
  50. // Float64Type indicates that the field carries a float64.
  51. Float64Type
  52. // Float32Type indicates that the field carries a float32.
  53. Float32Type
  54. // Int64Type indicates that the field carries an int64.
  55. Int64Type
  56. // Int32Type indicates that the field carries an int32.
  57. Int32Type
  58. // Int16Type indicates that the field carries an int16.
  59. Int16Type
  60. // Int8Type indicates that the field carries an int8.
  61. Int8Type
  62. // StringType indicates that the field carries a string.
  63. StringType
  64. // TimeType indicates that the field carries a time.Time that is
  65. // representable by a UnixNano() stored as an int64.
  66. TimeType
  67. // TimeFullType indicates that the field carries a time.Time stored as-is.
  68. TimeFullType
  69. // Uint64Type indicates that the field carries a uint64.
  70. Uint64Type
  71. // Uint32Type indicates that the field carries a uint32.
  72. Uint32Type
  73. // Uint16Type indicates that the field carries a uint16.
  74. Uint16Type
  75. // Uint8Type indicates that the field carries a uint8.
  76. Uint8Type
  77. // UintptrType indicates that the field carries a uintptr.
  78. UintptrType
  79. // ReflectType indicates that the field carries an interface{}, which should
  80. // be serialized using reflection.
  81. ReflectType
  82. // NamespaceType signals the beginning of an isolated namespace. All
  83. // subsequent fields should be added to the new namespace.
  84. NamespaceType
  85. // StringerType indicates that the field carries a fmt.Stringer.
  86. StringerType
  87. // ErrorType indicates that the field carries an error.
  88. ErrorType
  89. // SkipType indicates that the field is a no-op.
  90. SkipType
  91. // InlineMarshalerType indicates that the field carries an ObjectMarshaler
  92. // that should be inlined.
  93. InlineMarshalerType
  94. )
  95. // A Field is a marshaling operation used to add a key-value pair to a logger's
  96. // context. Most fields are lazily marshaled, so it's inexpensive to add fields
  97. // to disabled debug-level log statements.
  98. type Field struct {
  99. Key string
  100. Type FieldType
  101. Integer int64
  102. String string
  103. Interface interface{}
  104. }
  105. // AddTo exports a field through the ObjectEncoder interface. It's primarily
  106. // useful to library authors, and shouldn't be necessary in most applications.
  107. func (f Field) AddTo(enc ObjectEncoder) {
  108. var err error
  109. switch f.Type {
  110. case ArrayMarshalerType:
  111. err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler))
  112. case ObjectMarshalerType:
  113. err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler))
  114. case InlineMarshalerType:
  115. err = f.Interface.(ObjectMarshaler).MarshalLogObject(enc)
  116. case BinaryType:
  117. enc.AddBinary(f.Key, f.Interface.([]byte))
  118. case BoolType:
  119. enc.AddBool(f.Key, f.Integer == 1)
  120. case ByteStringType:
  121. enc.AddByteString(f.Key, f.Interface.([]byte))
  122. case Complex128Type:
  123. enc.AddComplex128(f.Key, f.Interface.(complex128))
  124. case Complex64Type:
  125. enc.AddComplex64(f.Key, f.Interface.(complex64))
  126. case DurationType:
  127. enc.AddDuration(f.Key, time.Duration(f.Integer))
  128. case Float64Type:
  129. enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer)))
  130. case Float32Type:
  131. enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer)))
  132. case Int64Type:
  133. enc.AddInt64(f.Key, f.Integer)
  134. case Int32Type:
  135. enc.AddInt32(f.Key, int32(f.Integer))
  136. case Int16Type:
  137. enc.AddInt16(f.Key, int16(f.Integer))
  138. case Int8Type:
  139. enc.AddInt8(f.Key, int8(f.Integer))
  140. case StringType:
  141. enc.AddString(f.Key, f.String)
  142. case TimeType:
  143. if f.Interface != nil {
  144. enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location)))
  145. } else {
  146. // Fall back to UTC if location is nil.
  147. enc.AddTime(f.Key, time.Unix(0, f.Integer))
  148. }
  149. case TimeFullType:
  150. enc.AddTime(f.Key, f.Interface.(time.Time))
  151. case Uint64Type:
  152. enc.AddUint64(f.Key, uint64(f.Integer))
  153. case Uint32Type:
  154. enc.AddUint32(f.Key, uint32(f.Integer))
  155. case Uint16Type:
  156. enc.AddUint16(f.Key, uint16(f.Integer))
  157. case Uint8Type:
  158. enc.AddUint8(f.Key, uint8(f.Integer))
  159. case UintptrType:
  160. enc.AddUintptr(f.Key, uintptr(f.Integer))
  161. case ReflectType:
  162. err = enc.AddReflected(f.Key, f.Interface)
  163. case NamespaceType:
  164. enc.OpenNamespace(f.Key)
  165. case StringerType:
  166. err = encodeStringer(f.Key, f.Interface, enc)
  167. case ErrorType:
  168. err = encodeError(f.Key, f.Interface.(error), enc)
  169. case SkipType:
  170. break
  171. default:
  172. panic(fmt.Sprintf("unknown field type: %v", f))
  173. }
  174. if err != nil {
  175. enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error())
  176. }
  177. }
  178. // Equals returns whether two fields are equal. For non-primitive types such as
  179. // errors, marshalers, or reflect types, it uses reflect.DeepEqual.
  180. func (f Field) Equals(other Field) bool {
  181. if f.Type != other.Type {
  182. return false
  183. }
  184. if f.Key != other.Key {
  185. return false
  186. }
  187. switch f.Type {
  188. case BinaryType, ByteStringType:
  189. return bytes.Equal(f.Interface.([]byte), other.Interface.([]byte))
  190. case ArrayMarshalerType, ObjectMarshalerType, ErrorType, ReflectType:
  191. return reflect.DeepEqual(f.Interface, other.Interface)
  192. default:
  193. return f == other
  194. }
  195. }
  196. func addFields(enc ObjectEncoder, fields []Field) {
  197. for i := range fields {
  198. fields[i].AddTo(enc)
  199. }
  200. }
  201. func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (retErr error) {
  202. // Try to capture panics (from nil references or otherwise) when calling
  203. // the String() method, similar to https://golang.org/src/fmt/print.go#L540
  204. defer func() {
  205. if err := recover(); err != nil {
  206. // If it's a nil pointer, just say "<nil>". The likeliest causes are a
  207. // Stringer that fails to guard against nil or a nil pointer for a
  208. // value receiver, and in either case, "<nil>" is a nice result.
  209. if v := reflect.ValueOf(stringer); v.Kind() == reflect.Ptr && v.IsNil() {
  210. enc.AddString(key, "<nil>")
  211. return
  212. }
  213. retErr = fmt.Errorf("PANIC=%v", err)
  214. }
  215. }()
  216. enc.AddString(key, stringer.(fmt.Stringer).String())
  217. return nil
  218. }