mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-28 16:00:22 +00:00
d62d688982
Bumps the github-dependencies group with 3 updates: [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2), [github.com/kubernetes-csi/csi-lib-utils](https://github.com/kubernetes-csi/csi-lib-utils) and [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo). Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.33.2 to 1.33.3 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/ivs/v1.33.2...service/ivs/v1.33.3) Updates `github.com/kubernetes-csi/csi-lib-utils` from 0.19.0 to 0.20.0 - [Release notes](https://github.com/kubernetes-csi/csi-lib-utils/releases) - [Commits](https://github.com/kubernetes-csi/csi-lib-utils/compare/v0.19.0...v0.20.0) Updates `github.com/onsi/ginkgo/v2` from 2.22.0 to 2.22.1 - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.22.0...v2.22.1) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/service/sts dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-dependencies - dependency-name: github.com/kubernetes-csi/csi-lib-utils dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-dependencies - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-dependencies ... Signed-off-by: dependabot[bot] <support@github.com>
453 lines
11 KiB
Go
453 lines
11 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
//go:generate stringer -type=ValueKind -trimprefix=ValueKind
|
|
|
|
package telemetry
|
|
|
|
import (
|
|
"bytes"
|
|
"cmp"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
"slices"
|
|
"strconv"
|
|
"unsafe"
|
|
)
|
|
|
|
// A Value represents a structured value.
|
|
// A zero value is valid and represents an empty value.
|
|
type Value struct {
|
|
// Ensure forward compatibility by explicitly making this not comparable.
|
|
noCmp [0]func() //nolint: unused // This is indeed used.
|
|
|
|
// num holds the value for Int64, Float64, and Bool. It holds the length
|
|
// for String, Bytes, Slice, Map.
|
|
num uint64
|
|
// any holds either the KindBool, KindInt64, KindFloat64, stringptr,
|
|
// bytesptr, sliceptr, or mapptr. If KindBool, KindInt64, or KindFloat64
|
|
// then the value of Value is in num as described above. Otherwise, it
|
|
// contains the value wrapped in the appropriate type.
|
|
any any
|
|
}
|
|
|
|
type (
|
|
// sliceptr represents a value in Value.any for KindString Values.
|
|
stringptr *byte
|
|
// bytesptr represents a value in Value.any for KindBytes Values.
|
|
bytesptr *byte
|
|
// sliceptr represents a value in Value.any for KindSlice Values.
|
|
sliceptr *Value
|
|
// mapptr represents a value in Value.any for KindMap Values.
|
|
mapptr *Attr
|
|
)
|
|
|
|
// ValueKind is the kind of a [Value].
|
|
type ValueKind int
|
|
|
|
// ValueKind values.
|
|
const (
|
|
ValueKindEmpty ValueKind = iota
|
|
ValueKindBool
|
|
ValueKindFloat64
|
|
ValueKindInt64
|
|
ValueKindString
|
|
ValueKindBytes
|
|
ValueKindSlice
|
|
ValueKindMap
|
|
)
|
|
|
|
var valueKindStrings = []string{
|
|
"Empty",
|
|
"Bool",
|
|
"Float64",
|
|
"Int64",
|
|
"String",
|
|
"Bytes",
|
|
"Slice",
|
|
"Map",
|
|
}
|
|
|
|
func (k ValueKind) String() string {
|
|
if k >= 0 && int(k) < len(valueKindStrings) {
|
|
return valueKindStrings[k]
|
|
}
|
|
return "<unknown telemetry.ValueKind>"
|
|
}
|
|
|
|
// StringValue returns a new [Value] for a string.
|
|
func StringValue(v string) Value {
|
|
return Value{
|
|
num: uint64(len(v)),
|
|
any: stringptr(unsafe.StringData(v)),
|
|
}
|
|
}
|
|
|
|
// IntValue returns a [Value] for an int.
|
|
func IntValue(v int) Value { return Int64Value(int64(v)) }
|
|
|
|
// Int64Value returns a [Value] for an int64.
|
|
func Int64Value(v int64) Value {
|
|
return Value{num: uint64(v), any: ValueKindInt64}
|
|
}
|
|
|
|
// Float64Value returns a [Value] for a float64.
|
|
func Float64Value(v float64) Value {
|
|
return Value{num: math.Float64bits(v), any: ValueKindFloat64}
|
|
}
|
|
|
|
// BoolValue returns a [Value] for a bool.
|
|
func BoolValue(v bool) Value { //nolint:revive // Not a control flag.
|
|
var n uint64
|
|
if v {
|
|
n = 1
|
|
}
|
|
return Value{num: n, any: ValueKindBool}
|
|
}
|
|
|
|
// BytesValue returns a [Value] for a byte slice. The passed slice must not be
|
|
// changed after it is passed.
|
|
func BytesValue(v []byte) Value {
|
|
return Value{
|
|
num: uint64(len(v)),
|
|
any: bytesptr(unsafe.SliceData(v)),
|
|
}
|
|
}
|
|
|
|
// SliceValue returns a [Value] for a slice of [Value]. The passed slice must
|
|
// not be changed after it is passed.
|
|
func SliceValue(vs ...Value) Value {
|
|
return Value{
|
|
num: uint64(len(vs)),
|
|
any: sliceptr(unsafe.SliceData(vs)),
|
|
}
|
|
}
|
|
|
|
// MapValue returns a new [Value] for a slice of key-value pairs. The passed
|
|
// slice must not be changed after it is passed.
|
|
func MapValue(kvs ...Attr) Value {
|
|
return Value{
|
|
num: uint64(len(kvs)),
|
|
any: mapptr(unsafe.SliceData(kvs)),
|
|
}
|
|
}
|
|
|
|
// AsString returns the value held by v as a string.
|
|
func (v Value) AsString() string {
|
|
if sp, ok := v.any.(stringptr); ok {
|
|
return unsafe.String(sp, v.num)
|
|
}
|
|
// TODO: error handle
|
|
return ""
|
|
}
|
|
|
|
// asString returns the value held by v as a string. It will panic if the Value
|
|
// is not KindString.
|
|
func (v Value) asString() string {
|
|
return unsafe.String(v.any.(stringptr), v.num)
|
|
}
|
|
|
|
// AsInt64 returns the value held by v as an int64.
|
|
func (v Value) AsInt64() int64 {
|
|
if v.Kind() != ValueKindInt64 {
|
|
// TODO: error handle
|
|
return 0
|
|
}
|
|
return v.asInt64()
|
|
}
|
|
|
|
// asInt64 returns the value held by v as an int64. If v is not of KindInt64,
|
|
// this will return garbage.
|
|
func (v Value) asInt64() int64 {
|
|
// Assumes v.num was a valid int64 (overflow not checked).
|
|
return int64(v.num) // nolint: gosec
|
|
}
|
|
|
|
// AsBool returns the value held by v as a bool.
|
|
func (v Value) AsBool() bool {
|
|
if v.Kind() != ValueKindBool {
|
|
// TODO: error handle
|
|
return false
|
|
}
|
|
return v.asBool()
|
|
}
|
|
|
|
// asBool returns the value held by v as a bool. If v is not of KindBool, this
|
|
// will return garbage.
|
|
func (v Value) asBool() bool { return v.num == 1 }
|
|
|
|
// AsFloat64 returns the value held by v as a float64.
|
|
func (v Value) AsFloat64() float64 {
|
|
if v.Kind() != ValueKindFloat64 {
|
|
// TODO: error handle
|
|
return 0
|
|
}
|
|
return v.asFloat64()
|
|
}
|
|
|
|
// asFloat64 returns the value held by v as a float64. If v is not of
|
|
// KindFloat64, this will return garbage.
|
|
func (v Value) asFloat64() float64 { return math.Float64frombits(v.num) }
|
|
|
|
// AsBytes returns the value held by v as a []byte.
|
|
func (v Value) AsBytes() []byte {
|
|
if sp, ok := v.any.(bytesptr); ok {
|
|
return unsafe.Slice((*byte)(sp), v.num)
|
|
}
|
|
// TODO: error handle
|
|
return nil
|
|
}
|
|
|
|
// asBytes returns the value held by v as a []byte. It will panic if the Value
|
|
// is not KindBytes.
|
|
func (v Value) asBytes() []byte {
|
|
return unsafe.Slice((*byte)(v.any.(bytesptr)), v.num)
|
|
}
|
|
|
|
// AsSlice returns the value held by v as a []Value.
|
|
func (v Value) AsSlice() []Value {
|
|
if sp, ok := v.any.(sliceptr); ok {
|
|
return unsafe.Slice((*Value)(sp), v.num)
|
|
}
|
|
// TODO: error handle
|
|
return nil
|
|
}
|
|
|
|
// asSlice returns the value held by v as a []Value. It will panic if the Value
|
|
// is not KindSlice.
|
|
func (v Value) asSlice() []Value {
|
|
return unsafe.Slice((*Value)(v.any.(sliceptr)), v.num)
|
|
}
|
|
|
|
// AsMap returns the value held by v as a []Attr.
|
|
func (v Value) AsMap() []Attr {
|
|
if sp, ok := v.any.(mapptr); ok {
|
|
return unsafe.Slice((*Attr)(sp), v.num)
|
|
}
|
|
// TODO: error handle
|
|
return nil
|
|
}
|
|
|
|
// asMap returns the value held by v as a []Attr. It will panic if the
|
|
// Value is not KindMap.
|
|
func (v Value) asMap() []Attr {
|
|
return unsafe.Slice((*Attr)(v.any.(mapptr)), v.num)
|
|
}
|
|
|
|
// Kind returns the Kind of v.
|
|
func (v Value) Kind() ValueKind {
|
|
switch x := v.any.(type) {
|
|
case ValueKind:
|
|
return x
|
|
case stringptr:
|
|
return ValueKindString
|
|
case bytesptr:
|
|
return ValueKindBytes
|
|
case sliceptr:
|
|
return ValueKindSlice
|
|
case mapptr:
|
|
return ValueKindMap
|
|
default:
|
|
return ValueKindEmpty
|
|
}
|
|
}
|
|
|
|
// Empty returns if v does not hold any value.
|
|
func (v Value) Empty() bool { return v.Kind() == ValueKindEmpty }
|
|
|
|
// Equal returns if v is equal to w.
|
|
func (v Value) Equal(w Value) bool {
|
|
k1 := v.Kind()
|
|
k2 := w.Kind()
|
|
if k1 != k2 {
|
|
return false
|
|
}
|
|
switch k1 {
|
|
case ValueKindInt64, ValueKindBool:
|
|
return v.num == w.num
|
|
case ValueKindString:
|
|
return v.asString() == w.asString()
|
|
case ValueKindFloat64:
|
|
return v.asFloat64() == w.asFloat64()
|
|
case ValueKindSlice:
|
|
return slices.EqualFunc(v.asSlice(), w.asSlice(), Value.Equal)
|
|
case ValueKindMap:
|
|
sv := sortMap(v.asMap())
|
|
sw := sortMap(w.asMap())
|
|
return slices.EqualFunc(sv, sw, Attr.Equal)
|
|
case ValueKindBytes:
|
|
return bytes.Equal(v.asBytes(), w.asBytes())
|
|
case ValueKindEmpty:
|
|
return true
|
|
default:
|
|
// TODO: error handle
|
|
return false
|
|
}
|
|
}
|
|
|
|
func sortMap(m []Attr) []Attr {
|
|
sm := make([]Attr, len(m))
|
|
copy(sm, m)
|
|
slices.SortFunc(sm, func(a, b Attr) int {
|
|
return cmp.Compare(a.Key, b.Key)
|
|
})
|
|
|
|
return sm
|
|
}
|
|
|
|
// String returns Value's value as a string, formatted like [fmt.Sprint].
|
|
//
|
|
// The returned string is meant for debugging;
|
|
// the string representation is not stable.
|
|
func (v Value) String() string {
|
|
switch v.Kind() {
|
|
case ValueKindString:
|
|
return v.asString()
|
|
case ValueKindInt64:
|
|
// Assumes v.num was a valid int64 (overflow not checked).
|
|
return strconv.FormatInt(int64(v.num), 10) // nolint: gosec
|
|
case ValueKindFloat64:
|
|
return strconv.FormatFloat(v.asFloat64(), 'g', -1, 64)
|
|
case ValueKindBool:
|
|
return strconv.FormatBool(v.asBool())
|
|
case ValueKindBytes:
|
|
return fmt.Sprint(v.asBytes())
|
|
case ValueKindMap:
|
|
return fmt.Sprint(v.asMap())
|
|
case ValueKindSlice:
|
|
return fmt.Sprint(v.asSlice())
|
|
case ValueKindEmpty:
|
|
return "<nil>"
|
|
default:
|
|
// Try to handle this as gracefully as possible.
|
|
//
|
|
// Don't panic here. The goal here is to have developers find this
|
|
// first if a slog.Kind is is not handled. It is
|
|
// preferable to have user's open issue asking why their attributes
|
|
// have a "unhandled: " prefix than say that their code is panicking.
|
|
return fmt.Sprintf("<unhandled telemetry.ValueKind: %s>", v.Kind())
|
|
}
|
|
}
|
|
|
|
// MarshalJSON encodes v into OTLP formatted JSON.
|
|
func (v *Value) MarshalJSON() ([]byte, error) {
|
|
switch v.Kind() {
|
|
case ValueKindString:
|
|
return json.Marshal(struct {
|
|
Value string `json:"stringValue"`
|
|
}{v.asString()})
|
|
case ValueKindInt64:
|
|
return json.Marshal(struct {
|
|
Value string `json:"intValue"`
|
|
}{strconv.FormatInt(int64(v.num), 10)})
|
|
case ValueKindFloat64:
|
|
return json.Marshal(struct {
|
|
Value float64 `json:"doubleValue"`
|
|
}{v.asFloat64()})
|
|
case ValueKindBool:
|
|
return json.Marshal(struct {
|
|
Value bool `json:"boolValue"`
|
|
}{v.asBool()})
|
|
case ValueKindBytes:
|
|
return json.Marshal(struct {
|
|
Value []byte `json:"bytesValue"`
|
|
}{v.asBytes()})
|
|
case ValueKindMap:
|
|
return json.Marshal(struct {
|
|
Value struct {
|
|
Values []Attr `json:"values"`
|
|
} `json:"kvlistValue"`
|
|
}{struct {
|
|
Values []Attr `json:"values"`
|
|
}{v.asMap()}})
|
|
case ValueKindSlice:
|
|
return json.Marshal(struct {
|
|
Value struct {
|
|
Values []Value `json:"values"`
|
|
} `json:"arrayValue"`
|
|
}{struct {
|
|
Values []Value `json:"values"`
|
|
}{v.asSlice()}})
|
|
case ValueKindEmpty:
|
|
return nil, nil
|
|
default:
|
|
return nil, fmt.Errorf("unknown Value kind: %s", v.Kind().String())
|
|
}
|
|
}
|
|
|
|
// UnmarshalJSON decodes the OTLP formatted JSON contained in data into v.
|
|
func (v *Value) UnmarshalJSON(data []byte) error {
|
|
decoder := json.NewDecoder(bytes.NewReader(data))
|
|
|
|
t, err := decoder.Token()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if t != json.Delim('{') {
|
|
return errors.New("invalid Value type")
|
|
}
|
|
|
|
for decoder.More() {
|
|
keyIface, err := decoder.Token()
|
|
if err != nil {
|
|
if errors.Is(err, io.EOF) {
|
|
// Empty.
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
key, ok := keyIface.(string)
|
|
if !ok {
|
|
return fmt.Errorf("invalid Value key: %#v", keyIface)
|
|
}
|
|
|
|
switch key {
|
|
case "stringValue", "string_value":
|
|
var val string
|
|
err = decoder.Decode(&val)
|
|
*v = StringValue(val)
|
|
case "boolValue", "bool_value":
|
|
var val bool
|
|
err = decoder.Decode(&val)
|
|
*v = BoolValue(val)
|
|
case "intValue", "int_value":
|
|
var val protoInt64
|
|
err = decoder.Decode(&val)
|
|
*v = Int64Value(val.Int64())
|
|
case "doubleValue", "double_value":
|
|
var val float64
|
|
err = decoder.Decode(&val)
|
|
*v = Float64Value(val)
|
|
case "bytesValue", "bytes_value":
|
|
var val64 string
|
|
if err := decoder.Decode(&val64); err != nil {
|
|
return err
|
|
}
|
|
var val []byte
|
|
val, err = base64.StdEncoding.DecodeString(val64)
|
|
*v = BytesValue(val)
|
|
case "arrayValue", "array_value":
|
|
var val struct{ Values []Value }
|
|
err = decoder.Decode(&val)
|
|
*v = SliceValue(val.Values...)
|
|
case "kvlistValue", "kvlist_value":
|
|
var val struct{ Values []Attr }
|
|
err = decoder.Decode(&val)
|
|
*v = MapValue(val.Values...)
|
|
default:
|
|
// Skip unknown.
|
|
continue
|
|
}
|
|
// Use first valid. Ignore the rest.
|
|
return err
|
|
}
|
|
|
|
// Only unknown fields. Return nil without unmarshaling any value.
|
|
return nil
|
|
}
|