VictoriaMetrics/vendor/go.opentelemetry.io/collector/pdata/pcommon/value.go
2023-09-07 13:01:39 +02:00

466 lines
13 KiB
Go

// 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 {
return newValue(&otlpcommon.AnyValue{})
}
// NewValueStr creates a new Value with the given string value.
func NewValueStr(v string) Value {
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_StringValue{StringValue: v}})
}
// NewValueInt creates a new Value with the given int64 value.
func NewValueInt(v int64) Value {
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_IntValue{IntValue: v}})
}
// NewValueDouble creates a new Value with the given float64 value.
func NewValueDouble(v float64) Value {
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_DoubleValue{DoubleValue: v}})
}
// NewValueBool creates a new Value with the given bool value.
func NewValueBool(v bool) Value {
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_BoolValue{BoolValue: v}})
}
// NewValueMap creates a new Value of map type.
func NewValueMap() Value {
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_KvlistValue{KvlistValue: &otlpcommon.KeyValueList{}}})
}
// NewValueSlice creates a new Value of array type.
func NewValueSlice() Value {
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{}}})
}
// NewValueBytes creates a new empty Value of byte type.
func NewValueBytes() Value {
return newValue(&otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_BytesValue{BytesValue: nil}})
}
func newValue(orig *otlpcommon.AnyValue) Value {
return Value(internal.NewValue(orig))
}
func (v Value) getOrig() *otlpcommon.AnyValue {
return internal.GetOrigValue(internal.Value(v))
}
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.
// Calling this function on zero-initialized Value will cause a panic.
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).
// Calling this function on zero-initialized Value will cause a panic.
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).
// Calling this function on zero-initialized Value will cause a panic.
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.
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) Bool() bool {
return v.getOrig().GetBoolValue()
}
// Map returns the map value associated with this Value.
// If the Type() is not ValueTypeMap then returns an invalid map. Note that using
// such map can cause panic.
//
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) Map() Map {
kvlist := v.getOrig().GetKvlistValue()
if kvlist == nil {
return Map{}
}
return newMap(&kvlist.Values)
}
// Slice returns the slice value associated with this Value.
// If the Type() is not ValueTypeSlice then returns an invalid slice. Note that using
// such slice can cause panic.
//
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) Slice() Slice {
arr := v.getOrig().GetArrayValue()
if arr == nil {
return Slice{}
}
return newSlice(&arr.Values)
}
// Bytes returns the ByteSlice value associated with this Value.
// If the Type() is not ValueTypeBytes then returns an invalid ByteSlice object. Note that using
// such slice can cause panic.
//
// Calling this function on zero-initialized Value will cause a panic.
func (v Value) Bytes() ByteSlice {
bv, ok := v.getOrig().GetValue().(*otlpcommon.AnyValue_BytesValue)
if !ok {
return ByteSlice{}
}
return ByteSlice(internal.NewByteSlice(&bv.BytesValue))
}
// 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.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.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.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.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 {
bv := otlpcommon.AnyValue_BytesValue{BytesValue: nil}
v.getOrig().Value = &bv
return ByteSlice(internal.NewByteSlice(&bv.BytesValue))
}
// 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 {
kv := &otlpcommon.AnyValue_KvlistValue{KvlistValue: &otlpcommon.KeyValueList{}}
v.getOrig().Value = kv
return newMap(&kv.KvlistValue.Values)
}
// 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 {
av := &otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{}}
v.getOrig().Value = av
return newSlice(&av.ArrayValue.Values)
}
// CopyTo copies the Value instance overriding the destination.
func (v Value) CopyTo(dest Value) {
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).CopyTo(newMap(&kv.KvlistValue.Values))
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).CopyTo(newSlice(&av.ArrayValue.Values))
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.
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}
akv := newValue(&orig.Value)
akv.SetStr(v)
return orig
}
func newKeyValueInt(k string, v int64) otlpcommon.KeyValue {
orig := otlpcommon.KeyValue{Key: k}
akv := newValue(&orig.Value)
akv.SetInt(v)
return orig
}
func newKeyValueDouble(k string, v float64) otlpcommon.KeyValue {
orig := otlpcommon.KeyValue{Key: k}
akv := newValue(&orig.Value)
akv.SetDouble(v)
return orig
}
func newKeyValueBool(k string, v bool) otlpcommon.KeyValue {
orig := otlpcommon.KeyValue{Key: k}
akv := newValue(&orig.Value)
akv.SetBool(v)
return orig
}