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