-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
value.go
483 lines (432 loc) · 14.4 KB
/
value.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package pcommon // import "go.opentelemetry.io/collector/pdata/pcommon"
import (
"encoding/base64"
"encoding/json"
"fmt"
"math"
"strconv"
"go.opentelemetry.io/collector/pdata/internal"
otlpcommon "go.opentelemetry.io/collector/pdata/internal/data/protogen/common/v1"
)
// ValueType specifies the type of Value.
type ValueType int32
const (
ValueTypeEmpty ValueType = iota
ValueTypeStr
ValueTypeInt
ValueTypeDouble
ValueTypeBool
ValueTypeMap
ValueTypeSlice
ValueTypeBytes
)
// String returns the string representation of the ValueType.
func (avt ValueType) String() string {
switch avt {
case ValueTypeEmpty:
return "Empty"
case ValueTypeStr:
return "Str"
case ValueTypeBool:
return "Bool"
case ValueTypeInt:
return "Int"
case ValueTypeDouble:
return "Double"
case ValueTypeMap:
return "Map"
case ValueTypeSlice:
return "Slice"
case ValueTypeBytes:
return "Bytes"
}
return ""
}
// Value is a mutable cell containing any value. Typically used as an element of Map or Slice.
// Must use one of NewValue+ functions below to create new instances.
//
// Intended to be passed by value since internally it is just a pointer to actual
// value representation. For the same reason passing by value and calling setters
// will modify the original, e.g.:
//
// func f1(val Value) { val.SetInt(234) }
// func f2() {
// v := NewValueStr("a string")
// f1(v)
// _ := v.Type() // this will return ValueTypeInt
// }
//
// Important: zero-initialized instance is not valid for use. All Value functions below must
// be called only on instances that are created via NewValue+ functions.
type Value internal.Value
// NewValueEmpty creates a new Value with an empty value.
func NewValueEmpty() Value {
state := internal.StateMutable
return newValue(&otlpcommon.AnyValue{}, &state)
}
// NewValueStr creates a new Value with the given string value.
func NewValueStr(v string) Value {
state := internal.StateMutable
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_StringValue{StringValue: v}}, &state)
}
// NewValueInt creates a new Value with the given int64 value.
func NewValueInt(v int64) Value {
state := internal.StateMutable
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_IntValue{IntValue: v}}, &state)
}
// NewValueDouble creates a new Value with the given float64 value.
func NewValueDouble(v float64) Value {
state := internal.StateMutable
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_DoubleValue{DoubleValue: v}}, &state)
}
// NewValueBool creates a new Value with the given bool value.
func NewValueBool(v bool) Value {
state := internal.StateMutable
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_BoolValue{BoolValue: v}}, &state)
}
// NewValueMap creates a new Value of map type.
func NewValueMap() Value {
state := internal.StateMutable
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_KvlistValue{KvlistValue: &otlpcommon.KeyValueList{}}}, &state)
}
// NewValueSlice creates a new Value of array type.
func NewValueSlice() Value {
state := internal.StateMutable
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{}}}, &state)
}
// NewValueBytes creates a new empty Value of byte type.
func NewValueBytes() Value {
state := internal.StateMutable
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_BytesValue{BytesValue: nil}}, &state)
}
func newValue(orig *otlpcommon.AnyValue, state *internal.State) Value {
return Value(internal.NewValue(orig, state))
}
func (v Value) getOrig() *otlpcommon.AnyValue {
return internal.GetOrigValue(internal.Value(v))
}
func (v Value) getState() *internal.State {
return internal.GetValueState(internal.Value(v))
}
// FromRaw sets the value from the given raw value.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) FromRaw(iv any) error {
switch tv := iv.(type) {
case nil:
v.getOrig().Value = nil
case string:
v.SetStr(tv)
case int:
v.SetInt(int64(tv))
case int8:
v.SetInt(int64(tv))
case int16:
v.SetInt(int64(tv))
case int32:
v.SetInt(int64(tv))
case int64:
v.SetInt(tv)
case uint:
v.SetInt(int64(tv))
case uint8:
v.SetInt(int64(tv))
case uint16:
v.SetInt(int64(tv))
case uint32:
v.SetInt(int64(tv))
case uint64:
v.SetInt(int64(tv))
case float32:
v.SetDouble(float64(tv))
case float64:
v.SetDouble(tv)
case bool:
v.SetBool(tv)
case []byte:
v.SetEmptyBytes().FromRaw(tv)
case map[string]any:
return v.SetEmptyMap().FromRaw(tv)
case []any:
return v.SetEmptySlice().FromRaw(tv)
default:
return fmt.Errorf("<Invalid value type %T>", tv)
}
return nil
}
// Type returns the type of the value for this Value.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) Type() ValueType {
switch v.getOrig().Value.(type) {
case *otlpcommon.AnyValue_StringValue:
return ValueTypeStr
case *otlpcommon.AnyValue_BoolValue:
return ValueTypeBool
case *otlpcommon.AnyValue_IntValue:
return ValueTypeInt
case *otlpcommon.AnyValue_DoubleValue:
return ValueTypeDouble
case *otlpcommon.AnyValue_KvlistValue:
return ValueTypeMap
case *otlpcommon.AnyValue_ArrayValue:
return ValueTypeSlice
case *otlpcommon.AnyValue_BytesValue:
return ValueTypeBytes
}
return ValueTypeEmpty
}
// Str returns the string value associated with this Value.
// The shorter name is used instead of String to avoid implementing fmt.Stringer interface.
// If the Type() is not ValueTypeStr then returns empty string.
func (v Value) Str() string {
return v.getOrig().GetStringValue()
}
// Int returns the int64 value associated with this Value.
// If the Type() is not ValueTypeInt then returns int64(0).
func (v Value) Int() int64 {
return v.getOrig().GetIntValue()
}
// Double returns the float64 value associated with this Value.
// If the Type() is not ValueTypeDouble then returns float64(0).
func (v Value) Double() float64 {
return v.getOrig().GetDoubleValue()
}
// Bool returns the bool value associated with this Value.
// If the Type() is not ValueTypeBool then returns false.
func (v Value) Bool() bool {
return v.getOrig().GetBoolValue()
}
// Map returns the map value associated with this Value.
// If the function is called on zero-initialized Value or if the Type() is not ValueTypeMap
// then it returns an invalid map. Note that using such map can cause panic.
func (v Value) Map() Map {
kvlist := v.getOrig().GetKvlistValue()
if kvlist == nil {
return Map{}
}
return newMap(&kvlist.Values, internal.GetValueState(internal.Value(v)))
}
// Slice returns the slice value associated with this Value.
// If the function is called on zero-initialized Value or if the Type() is not ValueTypeSlice
// then returns an invalid slice. Note that using such slice can cause panic.
func (v Value) Slice() Slice {
arr := v.getOrig().GetArrayValue()
if arr == nil {
return Slice{}
}
return newSlice(&arr.Values, internal.GetValueState(internal.Value(v)))
}
// Bytes returns the ByteSlice value associated with this Value.
// If the function is called on zero-initialized Value or if the Type() is not ValueTypeBytes
// then returns an invalid ByteSlice object. Note that using such slice can cause panic.
func (v Value) Bytes() ByteSlice {
bv, ok := v.getOrig().GetValue().(*otlpcommon.AnyValue_BytesValue)
if !ok {
return ByteSlice{}
}
return ByteSlice(internal.NewByteSlice(&bv.BytesValue, internal.GetValueState(internal.Value(v))))
}
// SetStr replaces the string value associated with this Value,
// it also changes the type to be ValueTypeStr.
// The shorter name is used instead of SetString to avoid implementing
// fmt.Stringer interface by the corresponding getter method.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) SetStr(sv string) {
v.getState().AssertMutable()
v.getOrig().Value = &otlpcommon.AnyValue_StringValue{StringValue: sv}
}
// SetInt replaces the int64 value associated with this Value,
// it also changes the type to be ValueTypeInt.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) SetInt(iv int64) {
v.getState().AssertMutable()
v.getOrig().Value = &otlpcommon.AnyValue_IntValue{IntValue: iv}
}
// SetDouble replaces the float64 value associated with this Value,
// it also changes the type to be ValueTypeDouble.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) SetDouble(dv float64) {
v.getState().AssertMutable()
v.getOrig().Value = &otlpcommon.AnyValue_DoubleValue{DoubleValue: dv}
}
// SetBool replaces the bool value associated with this Value,
// it also changes the type to be ValueTypeBool.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) SetBool(bv bool) {
v.getState().AssertMutable()
v.getOrig().Value = &otlpcommon.AnyValue_BoolValue{BoolValue: bv}
}
// SetEmptyBytes sets value to an empty byte slice and returns it.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) SetEmptyBytes() ByteSlice {
v.getState().AssertMutable()
bv := otlpcommon.AnyValue_BytesValue{BytesValue: nil}
v.getOrig().Value = &bv
return ByteSlice(internal.NewByteSlice(&bv.BytesValue, v.getState()))
}
// SetEmptyMap sets value to an empty map and returns it.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) SetEmptyMap() Map {
v.getState().AssertMutable()
kv := &otlpcommon.AnyValue_KvlistValue{KvlistValue: &otlpcommon.KeyValueList{}}
v.getOrig().Value = kv
return newMap(&kv.KvlistValue.Values, v.getState())
}
// SetEmptySlice sets value to an empty slice and returns it.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) SetEmptySlice() Slice {
v.getState().AssertMutable()
av := &otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{}}
v.getOrig().Value = av
return newSlice(&av.ArrayValue.Values, v.getState())
}
// CopyTo copies the Value instance overriding the destination.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) CopyTo(dest Value) {
dest.getState().AssertMutable()
destOrig := dest.getOrig()
switch ov := v.getOrig().Value.(type) {
case *otlpcommon.AnyValue_KvlistValue:
kv, ok := destOrig.Value.(*otlpcommon.AnyValue_KvlistValue)
if !ok {
kv = &otlpcommon.AnyValue_KvlistValue{KvlistValue: &otlpcommon.KeyValueList{}}
destOrig.Value = kv
}
if ov.KvlistValue == nil {
kv.KvlistValue = nil
return
}
// Deep copy to dest.
newMap(&ov.KvlistValue.Values, v.getState()).CopyTo(newMap(&kv.KvlistValue.Values, dest.getState()))
case *otlpcommon.AnyValue_ArrayValue:
av, ok := destOrig.Value.(*otlpcommon.AnyValue_ArrayValue)
if !ok {
av = &otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{}}
destOrig.Value = av
}
if ov.ArrayValue == nil {
av.ArrayValue = nil
return
}
// Deep copy to dest.
newSlice(&ov.ArrayValue.Values, v.getState()).CopyTo(newSlice(&av.ArrayValue.Values, dest.getState()))
case *otlpcommon.AnyValue_BytesValue:
bv, ok := destOrig.Value.(*otlpcommon.AnyValue_BytesValue)
if !ok {
bv = &otlpcommon.AnyValue_BytesValue{}
destOrig.Value = bv
}
bv.BytesValue = make([]byte, len(ov.BytesValue))
copy(bv.BytesValue, ov.BytesValue)
default:
// Primitive immutable type, no need for deep copy.
destOrig.Value = ov
}
}
// AsString converts an OTLP Value object of any type to its equivalent string
// representation. This differs from Str which only returns a non-empty value
// if the ValueType is ValueTypeStr.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) AsString() string {
switch v.Type() {
case ValueTypeEmpty:
return ""
case ValueTypeStr:
return v.Str()
case ValueTypeBool:
return strconv.FormatBool(v.Bool())
case ValueTypeDouble:
return float64AsString(v.Double())
case ValueTypeInt:
return strconv.FormatInt(v.Int(), 10)
case ValueTypeMap:
jsonStr, _ := json.Marshal(v.Map().AsRaw())
return string(jsonStr)
case ValueTypeBytes:
return base64.StdEncoding.EncodeToString(*v.Bytes().getOrig())
case ValueTypeSlice:
jsonStr, _ := json.Marshal(v.Slice().AsRaw())
return string(jsonStr)
default:
return fmt.Sprintf("<Unknown OpenTelemetry attribute value type %q>", v.Type())
}
}
// See https://cs.opensource.google/go/go/+/refs/tags/go1.17.7:src/encoding/json/encode.go;l=585.
// This allows us to avoid using reflection.
func float64AsString(f float64) string {
if math.IsInf(f, 0) || math.IsNaN(f) {
return fmt.Sprintf("json: unsupported value: %s", strconv.FormatFloat(f, 'g', -1, 64))
}
// Convert as if by ES6 number to string conversion.
// This matches most other JSON generators.
// See golang.org/issue/6384 and golang.org/issue/14135.
// Like fmt %g, but the exponent cutoffs are different
// and exponents themselves are not padded to two digits.
scratch := [64]byte{}
b := scratch[:0]
abs := math.Abs(f)
fmt := byte('f')
if abs != 0 && (abs < 1e-6 || abs >= 1e21) {
fmt = 'e'
}
b = strconv.AppendFloat(b, f, fmt, -1, 64)
if fmt == 'e' {
// clean up e-09 to e-9
n := len(b)
if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' {
b[n-2] = b[n-1]
b = b[:n-1]
}
}
return string(b)
}
func (v Value) AsRaw() any {
switch v.Type() {
case ValueTypeEmpty:
return nil
case ValueTypeStr:
return v.Str()
case ValueTypeBool:
return v.Bool()
case ValueTypeDouble:
return v.Double()
case ValueTypeInt:
return v.Int()
case ValueTypeBytes:
return v.Bytes().AsRaw()
case ValueTypeMap:
return v.Map().AsRaw()
case ValueTypeSlice:
return v.Slice().AsRaw()
}
return fmt.Sprintf("<Unknown OpenTelemetry value type %q>", v.Type())
}
func newKeyValueString(k string, v string) otlpcommon.KeyValue {
orig := otlpcommon.KeyValue{Key: k}
state := internal.StateMutable
akv := newValue(&orig.Value, &state)
akv.SetStr(v)
return orig
}
func newKeyValueInt(k string, v int64) otlpcommon.KeyValue {
orig := otlpcommon.KeyValue{Key: k}
state := internal.StateMutable
akv := newValue(&orig.Value, &state)
akv.SetInt(v)
return orig
}
func newKeyValueDouble(k string, v float64) otlpcommon.KeyValue {
orig := otlpcommon.KeyValue{Key: k}
state := internal.StateMutable
akv := newValue(&orig.Value, &state)
akv.SetDouble(v)
return orig
}
func newKeyValueBool(k string, v bool) otlpcommon.KeyValue {
orig := otlpcommon.KeyValue{Key: k}
state := internal.StateMutable
akv := newValue(&orig.Value, &state)
akv.SetBool(v)
return orig
}