1 // Copyright The OpenTelemetry Authors
2 // SPDX-License-Identifier: Apache-2.0
3 4 package telemetry // import "go.opentelemetry.io/otel/trace/internal/telemetry"
5 6 import (
7 "bytes"
8 "cmp"
9 "encoding/base64"
10 "encoding/json"
11 "errors"
12 "fmt"
13 "io"
14 "math"
15 "slices"
16 "strconv"
17 "unsafe"
18 )
19 20 // A Value represents a structured value.
21 // A zero value is valid and represents an empty value.
22 type Value struct {
23 // Ensure forward compatibility by explicitly making this not comparable.
24 noCmp [0]func() //nolint: unused // This is indeed used.
25 26 // num holds the value for Int64, Float64, and Bool. It holds the length
27 // for String, Bytes, Slice, Map.
28 num uint64
29 // any holds either the KindBool, KindInt64, KindFloat64, stringptr,
30 // bytesptr, sliceptr, or mapptr. If KindBool, KindInt64, or KindFloat64
31 // then the value of Value is in num as described above. Otherwise, it
32 // contains the value wrapped in the appropriate type.
33 any any
34 }
35 36 type (
37 // sliceptr represents a value in Value.any for KindString Values.
38 stringptr *byte
39 // bytesptr represents a value in Value.any for KindBytes Values.
40 bytesptr *byte
41 // sliceptr represents a value in Value.any for KindSlice Values.
42 sliceptr *Value
43 // mapptr represents a value in Value.any for KindMap Values.
44 mapptr *Attr
45 )
46 47 // ValueKind is the kind of a [Value].
48 type ValueKind int
49 50 // ValueKind values.
51 const (
52 ValueKindEmpty ValueKind = iota
53 ValueKindBool
54 ValueKindFloat64
55 ValueKindInt64
56 ValueKindString
57 ValueKindBytes
58 ValueKindSlice
59 ValueKindMap
60 )
61 62 var valueKindStrings = []string{
63 "Empty",
64 "Bool",
65 "Float64",
66 "Int64",
67 "String",
68 "Bytes",
69 "Slice",
70 "Map",
71 }
72 73 func (k ValueKind) String() string {
74 if k >= 0 && int(k) < len(valueKindStrings) {
75 return valueKindStrings[k]
76 }
77 return "<unknown telemetry.ValueKind>"
78 }
79 80 // StringValue returns a new [Value] for a string.
81 func StringValue(v string) Value {
82 return Value{
83 num: uint64(len(v)),
84 any: stringptr(unsafe.StringData(v)),
85 }
86 }
87 88 // IntValue returns a [Value] for an int.
89 func IntValue(v int) Value { return Int64Value(int64(v)) }
90 91 // Int64Value returns a [Value] for an int64.
92 func Int64Value(v int64) Value {
93 return Value{
94 num: uint64(v), // nolint: gosec // Store raw bytes.
95 any: ValueKindInt64,
96 }
97 }
98 99 // Float64Value returns a [Value] for a float64.
100 func Float64Value(v float64) Value {
101 return Value{num: math.Float64bits(v), any: ValueKindFloat64}
102 }
103 104 // BoolValue returns a [Value] for a bool.
105 func BoolValue(v bool) Value { //nolint:revive // Not a control flag.
106 var n uint64
107 if v {
108 n = 1
109 }
110 return Value{num: n, any: ValueKindBool}
111 }
112 113 // BytesValue returns a [Value] for a byte slice. The passed slice must not be
114 // changed after it is passed.
115 func BytesValue(v []byte) Value {
116 return Value{
117 num: uint64(len(v)),
118 any: bytesptr(unsafe.SliceData(v)),
119 }
120 }
121 122 // SliceValue returns a [Value] for a slice of [Value]. The passed slice must
123 // not be changed after it is passed.
124 func SliceValue(vs ...Value) Value {
125 return Value{
126 num: uint64(len(vs)),
127 any: sliceptr(unsafe.SliceData(vs)),
128 }
129 }
130 131 // MapValue returns a new [Value] for a slice of key-value pairs. The passed
132 // slice must not be changed after it is passed.
133 func MapValue(kvs ...Attr) Value {
134 return Value{
135 num: uint64(len(kvs)),
136 any: mapptr(unsafe.SliceData(kvs)),
137 }
138 }
139 140 // AsString returns the value held by v as a string.
141 func (v Value) AsString() string {
142 if sp, ok := v.any.(stringptr); ok {
143 return unsafe.String(sp, v.num)
144 }
145 // TODO: error handle
146 return ""
147 }
148 149 // asString returns the value held by v as a string. It will panic if the Value
150 // is not KindString.
151 func (v Value) asString() string {
152 return unsafe.String(v.any.(stringptr), v.num)
153 }
154 155 // AsInt64 returns the value held by v as an int64.
156 func (v Value) AsInt64() int64 {
157 if v.Kind() != ValueKindInt64 {
158 // TODO: error handle
159 return 0
160 }
161 return v.asInt64()
162 }
163 164 // asInt64 returns the value held by v as an int64. If v is not of KindInt64,
165 // this will return garbage.
166 func (v Value) asInt64() int64 {
167 // Assumes v.num was a valid int64 (overflow not checked).
168 return int64(v.num) // nolint: gosec
169 }
170 171 // AsBool returns the value held by v as a bool.
172 func (v Value) AsBool() bool {
173 if v.Kind() != ValueKindBool {
174 // TODO: error handle
175 return false
176 }
177 return v.asBool()
178 }
179 180 // asBool returns the value held by v as a bool. If v is not of KindBool, this
181 // will return garbage.
182 func (v Value) asBool() bool { return v.num == 1 }
183 184 // AsFloat64 returns the value held by v as a float64.
185 func (v Value) AsFloat64() float64 {
186 if v.Kind() != ValueKindFloat64 {
187 // TODO: error handle
188 return 0
189 }
190 return v.asFloat64()
191 }
192 193 // asFloat64 returns the value held by v as a float64. If v is not of
194 // KindFloat64, this will return garbage.
195 func (v Value) asFloat64() float64 { return math.Float64frombits(v.num) }
196 197 // AsBytes returns the value held by v as a []byte.
198 func (v Value) AsBytes() []byte {
199 if sp, ok := v.any.(bytesptr); ok {
200 return unsafe.Slice((*byte)(sp), v.num)
201 }
202 // TODO: error handle
203 return nil
204 }
205 206 // asBytes returns the value held by v as a []byte. It will panic if the Value
207 // is not KindBytes.
208 func (v Value) asBytes() []byte {
209 return unsafe.Slice((*byte)(v.any.(bytesptr)), v.num)
210 }
211 212 // AsSlice returns the value held by v as a []Value.
213 func (v Value) AsSlice() []Value {
214 if sp, ok := v.any.(sliceptr); ok {
215 return unsafe.Slice((*Value)(sp), v.num)
216 }
217 // TODO: error handle
218 return nil
219 }
220 221 // asSlice returns the value held by v as a []Value. It will panic if the Value
222 // is not KindSlice.
223 func (v Value) asSlice() []Value {
224 return unsafe.Slice((*Value)(v.any.(sliceptr)), v.num)
225 }
226 227 // AsMap returns the value held by v as a []Attr.
228 func (v Value) AsMap() []Attr {
229 if sp, ok := v.any.(mapptr); ok {
230 return unsafe.Slice((*Attr)(sp), v.num)
231 }
232 // TODO: error handle
233 return nil
234 }
235 236 // asMap returns the value held by v as a []Attr. It will panic if the
237 // Value is not KindMap.
238 func (v Value) asMap() []Attr {
239 return unsafe.Slice((*Attr)(v.any.(mapptr)), v.num)
240 }
241 242 // Kind returns the Kind of v.
243 func (v Value) Kind() ValueKind {
244 switch x := v.any.(type) {
245 case ValueKind:
246 return x
247 case stringptr:
248 return ValueKindString
249 case bytesptr:
250 return ValueKindBytes
251 case sliceptr:
252 return ValueKindSlice
253 case mapptr:
254 return ValueKindMap
255 default:
256 return ValueKindEmpty
257 }
258 }
259 260 // Empty reports whether v does not hold any value.
261 func (v Value) Empty() bool { return v.Kind() == ValueKindEmpty }
262 263 // Equal reports whether v is equal to w.
264 func (v Value) Equal(w Value) bool {
265 k1 := v.Kind()
266 k2 := w.Kind()
267 if k1 != k2 {
268 return false
269 }
270 switch k1 {
271 case ValueKindInt64, ValueKindBool:
272 return v.num == w.num
273 case ValueKindString:
274 return v.asString() == w.asString()
275 case ValueKindFloat64:
276 return v.asFloat64() == w.asFloat64()
277 case ValueKindSlice:
278 return slices.EqualFunc(v.asSlice(), w.asSlice(), Value.Equal)
279 case ValueKindMap:
280 sv := sortMap(v.asMap())
281 sw := sortMap(w.asMap())
282 return slices.EqualFunc(sv, sw, Attr.Equal)
283 case ValueKindBytes:
284 return bytes.Equal(v.asBytes(), w.asBytes())
285 case ValueKindEmpty:
286 return true
287 default:
288 // TODO: error handle
289 return false
290 }
291 }
292 293 func sortMap(m []Attr) []Attr {
294 sm := make([]Attr, len(m))
295 copy(sm, m)
296 slices.SortFunc(sm, func(a, b Attr) int {
297 return cmp.Compare(a.Key, b.Key)
298 })
299 300 return sm
301 }
302 303 // String returns Value's value as a string, formatted like [fmt.Sprint].
304 //
305 // The returned string is meant for debugging;
306 // the string representation is not stable.
307 func (v Value) String() string {
308 switch v.Kind() {
309 case ValueKindString:
310 return v.asString()
311 case ValueKindInt64:
312 // Assumes v.num was a valid int64 (overflow not checked).
313 return strconv.FormatInt(int64(v.num), 10) // nolint: gosec
314 case ValueKindFloat64:
315 return strconv.FormatFloat(v.asFloat64(), 'g', -1, 64)
316 case ValueKindBool:
317 return strconv.FormatBool(v.asBool())
318 case ValueKindBytes:
319 return string(v.asBytes())
320 case ValueKindMap:
321 return fmt.Sprint(v.asMap())
322 case ValueKindSlice:
323 return fmt.Sprint(v.asSlice())
324 case ValueKindEmpty:
325 return "<nil>"
326 default:
327 // Try to handle this as gracefully as possible.
328 //
329 // Don't panic here. The goal here is to have developers find this
330 // first if a slog.Kind is is not handled. It is
331 // preferable to have user's open issue asking why their attributes
332 // have a "unhandled: " prefix than say that their code is panicking.
333 return fmt.Sprintf("<unhandled telemetry.ValueKind: %s>", v.Kind())
334 }
335 }
336 337 // MarshalJSON encodes v into OTLP formatted JSON.
338 func (v *Value) MarshalJSON() ([]byte, error) {
339 switch v.Kind() {
340 case ValueKindString:
341 return json.Marshal(struct {
342 Value string `json:"stringValue"`
343 }{v.asString()})
344 case ValueKindInt64:
345 return json.Marshal(struct {
346 Value string `json:"intValue"`
347 }{strconv.FormatInt(int64(v.num), 10)}) // nolint: gosec // From raw bytes.
348 case ValueKindFloat64:
349 return json.Marshal(struct {
350 Value float64 `json:"doubleValue"`
351 }{v.asFloat64()})
352 case ValueKindBool:
353 return json.Marshal(struct {
354 Value bool `json:"boolValue"`
355 }{v.asBool()})
356 case ValueKindBytes:
357 return json.Marshal(struct {
358 Value []byte `json:"bytesValue"`
359 }{v.asBytes()})
360 case ValueKindMap:
361 return json.Marshal(struct {
362 Value struct {
363 Values []Attr `json:"values"`
364 } `json:"kvlistValue"`
365 }{struct {
366 Values []Attr `json:"values"`
367 }{v.asMap()}})
368 case ValueKindSlice:
369 return json.Marshal(struct {
370 Value struct {
371 Values []Value `json:"values"`
372 } `json:"arrayValue"`
373 }{struct {
374 Values []Value `json:"values"`
375 }{v.asSlice()}})
376 case ValueKindEmpty:
377 return nil, nil
378 default:
379 return nil, fmt.Errorf("unknown Value kind: %s", v.Kind().String())
380 }
381 }
382 383 // UnmarshalJSON decodes the OTLP formatted JSON contained in data into v.
384 func (v *Value) UnmarshalJSON(data []byte) error {
385 decoder := json.NewDecoder(bytes.NewReader(data))
386 387 t, err := decoder.Token()
388 if err != nil {
389 return err
390 }
391 if t != json.Delim('{') {
392 return errors.New("invalid Value type")
393 }
394 395 for decoder.More() {
396 keyIface, err := decoder.Token()
397 if err != nil {
398 if errors.Is(err, io.EOF) {
399 // Empty.
400 return nil
401 }
402 return err
403 }
404 405 key, ok := keyIface.(string)
406 if !ok {
407 return fmt.Errorf("invalid Value key: %#v", keyIface)
408 }
409 410 switch key {
411 case "stringValue", "string_value":
412 var val string
413 err = decoder.Decode(&val)
414 *v = StringValue(val)
415 case "boolValue", "bool_value":
416 var val bool
417 err = decoder.Decode(&val)
418 *v = BoolValue(val)
419 case "intValue", "int_value":
420 var val protoInt64
421 err = decoder.Decode(&val)
422 *v = Int64Value(val.Int64())
423 case "doubleValue", "double_value":
424 var val float64
425 err = decoder.Decode(&val)
426 *v = Float64Value(val)
427 case "bytesValue", "bytes_value":
428 var val64 string
429 if err := decoder.Decode(&val64); err != nil {
430 return err
431 }
432 var val []byte
433 val, err = base64.StdEncoding.DecodeString(val64)
434 *v = BytesValue(val)
435 case "arrayValue", "array_value":
436 var val struct{ Values []Value }
437 err = decoder.Decode(&val)
438 *v = SliceValue(val.Values...)
439 case "kvlistValue", "kvlist_value":
440 var val struct{ Values []Attr }
441 err = decoder.Decode(&val)
442 *v = MapValue(val.Values...)
443 default:
444 // Skip unknown.
445 continue
446 }
447 // Use first valid. Ignore the rest.
448 return err
449 }
450 451 // Only unknown fields. Return nil without unmarshaling any value.
452 return nil
453 }
454