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