1package lightstep 2 3import ( 4 "encoding/json" 5 "fmt" 6 7 "github.com/lightstep/lightstep-tracer-common/golang/gogo/collectorpb" 8 "github.com/opentracing/opentracing-go/log" 9) 10 11const ( 12 ellipsis = "…" 13) 14 15// An implementation of the log.Encoder interface 16type grpcLogFieldEncoder struct { 17 converter *protoConverter 18 buffer *reportBuffer 19 keyValues []*collectorpb.KeyValue 20} 21 22func marshalFields( 23 converter *protoConverter, 24 protoLog *collectorpb.Log, 25 fields []log.Field, 26 buffer *reportBuffer, 27) { 28 logFieldEncoder := grpcLogFieldEncoder{ 29 converter: converter, 30 buffer: buffer, 31 keyValues: make([]*collectorpb.KeyValue, 0, len(fields)), 32 } 33 for _, field := range fields { 34 field.Marshal(&logFieldEncoder) 35 } 36 protoLog.Fields = logFieldEncoder.keyValues 37} 38 39func (lfe *grpcLogFieldEncoder) EmitString(key, value string) { 40 var keyValue collectorpb.KeyValue 41 lfe.setSafeKey(&keyValue, key) 42 lfe.setSafeStringValue(&keyValue, value) 43 lfe.emitKeyValue(&keyValue) 44} 45 46func (lfe *grpcLogFieldEncoder) EmitBool(key string, value bool) { 47 var keyValue collectorpb.KeyValue 48 lfe.setSafeKey(&keyValue, key) 49 keyValue.Value = &collectorpb.KeyValue_BoolValue{BoolValue: value} 50 lfe.emitKeyValue(&keyValue) 51} 52 53func (lfe *grpcLogFieldEncoder) EmitInt(key string, value int) { 54 var keyValue collectorpb.KeyValue 55 lfe.setSafeKey(&keyValue, key) 56 keyValue.Value = &collectorpb.KeyValue_IntValue{IntValue: int64(value)} 57 lfe.emitKeyValue(&keyValue) 58} 59 60func (lfe *grpcLogFieldEncoder) EmitInt32(key string, value int32) { 61 var keyValue collectorpb.KeyValue 62 lfe.setSafeKey(&keyValue, key) 63 keyValue.Value = &collectorpb.KeyValue_IntValue{IntValue: int64(value)} 64 lfe.emitKeyValue(&keyValue) 65} 66 67func (lfe *grpcLogFieldEncoder) EmitInt64(key string, value int64) { 68 var keyValue collectorpb.KeyValue 69 lfe.setSafeKey(&keyValue, key) 70 keyValue.Value = &collectorpb.KeyValue_IntValue{IntValue: value} 71 lfe.emitKeyValue(&keyValue) 72} 73 74// N.B. We are using a string encoding for 32- and 64-bit unsigned 75// integers because it will require a protocol change to treat this 76// properly. Revisit this after the OC/OT merger. LS-1175 77// 78// We could safely continue using the int64 value to represent uint32 79// without breaking the stringified representation, but for 80// consistency with uint64, we're encoding all unsigned integers as 81// strings. 82func (lfe *grpcLogFieldEncoder) EmitUint32(key string, value uint32) { 83 var keyValue collectorpb.KeyValue 84 lfe.setSafeKey(&keyValue, key) 85 keyValue.Value = &collectorpb.KeyValue_StringValue{StringValue: fmt.Sprint(value)} 86 lfe.emitKeyValue(&keyValue) 87} 88 89func (lfe *grpcLogFieldEncoder) EmitUint64(key string, value uint64) { 90 var keyValue collectorpb.KeyValue 91 lfe.setSafeKey(&keyValue, key) 92 keyValue.Value = &collectorpb.KeyValue_StringValue{StringValue: fmt.Sprint(value)} 93 lfe.emitKeyValue(&keyValue) 94} 95 96func (lfe *grpcLogFieldEncoder) EmitFloat32(key string, value float32) { 97 var keyValue collectorpb.KeyValue 98 lfe.setSafeKey(&keyValue, key) 99 keyValue.Value = &collectorpb.KeyValue_DoubleValue{DoubleValue: float64(value)} 100 lfe.emitKeyValue(&keyValue) 101} 102 103func (lfe *grpcLogFieldEncoder) EmitFloat64(key string, value float64) { 104 var keyValue collectorpb.KeyValue 105 lfe.setSafeKey(&keyValue, key) 106 keyValue.Value = &collectorpb.KeyValue_DoubleValue{DoubleValue: value} 107 lfe.emitKeyValue(&keyValue) 108} 109 110func (lfe *grpcLogFieldEncoder) EmitObject(key string, value interface{}) { 111 var keyValue collectorpb.KeyValue 112 lfe.setSafeKey(&keyValue, key) 113 jsonBytes, err := json.Marshal(value) 114 if err != nil { 115 emitEvent(newEventUnsupportedValue(key, value, err)) 116 lfe.buffer.logEncoderErrorCount++ 117 lfe.setSafeStringValue(&keyValue, "<json.Marshal error>") 118 lfe.emitKeyValue(&keyValue) 119 return 120 } 121 lfe.setSafeJSONValue(&keyValue, string(jsonBytes)) 122 lfe.emitKeyValue(&keyValue) 123} 124func (lfe *grpcLogFieldEncoder) EmitLazyLogger(value log.LazyLogger) { 125 // Delegate to `value` to do the late-bound encoding. 126 value(lfe) 127} 128 129func (lfe *grpcLogFieldEncoder) setSafeStringValue(keyValue *collectorpb.KeyValue, str string) { 130 if lfe.converter.maxLogValueLen > 0 && len(str) > lfe.converter.maxLogValueLen { 131 str = str[:(lfe.converter.maxLogValueLen-1)] + ellipsis 132 } 133 keyValue.Value = &collectorpb.KeyValue_StringValue{StringValue: str} 134} 135 136func (lfe *grpcLogFieldEncoder) setSafeJSONValue(keyValue *collectorpb.KeyValue, json string) { 137 if lfe.converter.maxLogValueLen > 0 && len(json) > lfe.converter.maxLogValueLen { 138 str := json[:(lfe.converter.maxLogValueLen-1)] + ellipsis 139 keyValue.Value = &collectorpb.KeyValue_StringValue{StringValue: str} 140 return 141 } 142 keyValue.Value = &collectorpb.KeyValue_JsonValue{JsonValue: json} 143} 144 145func (lfe *grpcLogFieldEncoder) setSafeKey(keyValue *collectorpb.KeyValue, key string) { 146 if lfe.converter.maxLogKeyLen > 0 && len(key) > lfe.converter.maxLogKeyLen { 147 keyValue.Key = key[:(lfe.converter.maxLogKeyLen-1)] + ellipsis 148 return 149 } 150 keyValue.Key = key 151} 152 153func (lfe *grpcLogFieldEncoder) emitKeyValue(keyValue *collectorpb.KeyValue) { 154 lfe.keyValues = append(lfe.keyValues, keyValue) 155} 156