You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-09-16 09:26:25 +02:00
Added support array attributes (#798)
* Added support array attributes * Changed function signature for AsArray attribute * Fixed code comments for array attributes * Fixed typos in comments in value.go Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
This commit is contained in:
@@ -158,3 +158,16 @@ func (k Key) Uint(v uint) KeyValue {
|
||||
func (k Key) Defined() bool {
|
||||
return len(k) != 0
|
||||
}
|
||||
|
||||
// Array creates a KeyValue instance with a ARRAY Value.
|
||||
//
|
||||
// If creating both key and a array value at the same time, then
|
||||
// instead of calling kv.Key(name).String(value) consider using a
|
||||
// convenience function provided by the api/key package -
|
||||
// key.Array(name, value).
|
||||
func (k Key) Array(v interface{}) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: value.Array(v),
|
||||
}
|
||||
}
|
||||
|
@@ -95,6 +95,12 @@ func Uint(k string, v uint) KeyValue {
|
||||
return Key(k).Uint(v)
|
||||
}
|
||||
|
||||
// Array creates a new key-value pair with a passed name and a array.
|
||||
// Only arrays of primitive type are supported.
|
||||
func Array(k string, v interface{}) KeyValue {
|
||||
return Key(k).Array(v)
|
||||
}
|
||||
|
||||
// Infer creates a new key-value pair instance with a passed name and
|
||||
// automatic type inference. This is slower, and not type-safe.
|
||||
func Infer(k string, value interface{}) KeyValue {
|
||||
@@ -109,6 +115,8 @@ func Infer(k string, value interface{}) KeyValue {
|
||||
rv := reflect.ValueOf(value)
|
||||
|
||||
switch rv.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return Array(k, value)
|
||||
case reflect.Bool:
|
||||
return Bool(k, rv.Bool())
|
||||
case reflect.Int, reflect.Int8, reflect.Int16:
|
||||
|
@@ -17,11 +17,12 @@ func _() {
|
||||
_ = x[FLOAT32-6]
|
||||
_ = x[FLOAT64-7]
|
||||
_ = x[STRING-8]
|
||||
_ = x[ARRAY-9]
|
||||
}
|
||||
|
||||
const _Type_name = "INVALIDBOOLINT32INT64UINT32UINT64FLOAT32FLOAT64STRING"
|
||||
const _Type_name = "INVALIDBOOLINT32INT64UINT32UINT64FLOAT32FLOAT64STRINGARRAY"
|
||||
|
||||
var _Type_index = [...]uint8{0, 7, 11, 16, 21, 27, 33, 40, 47, 53}
|
||||
var _Type_index = [...]uint8{0, 7, 11, 16, 21, 27, 33, 40, 47, 53, 58}
|
||||
|
||||
func (i Type) String() string {
|
||||
if i < 0 || i >= Type(len(_Type_index)-1) {
|
||||
|
@@ -17,7 +17,9 @@ package value
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"go.opentelemetry.io/otel/api/internal"
|
||||
@@ -34,6 +36,8 @@ type Value struct {
|
||||
numeric uint64
|
||||
stringly string
|
||||
// TODO Lazy value type?
|
||||
|
||||
array interface{}
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -46,6 +50,7 @@ const (
|
||||
FLOAT32 // 32 bit floating point value, use AsFloat32() to get it.
|
||||
FLOAT64 // 64 bit floating point value, use AsFloat64() to get it.
|
||||
STRING // String value, use AsString() to get it.
|
||||
ARRAY // Array value of arbitrary type, use AsArray() to get it.
|
||||
)
|
||||
|
||||
// Bool creates a BOOL Value.
|
||||
@@ -130,6 +135,32 @@ func Uint(v uint) Value {
|
||||
return Uint64(uint64(v))
|
||||
}
|
||||
|
||||
// Array creates an ARRAY value.
|
||||
func Array(array interface{}) Value {
|
||||
switch reflect.TypeOf(array).Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
isValidType := func() bool {
|
||||
// get array type regardless of dimensions
|
||||
typeName := reflect.TypeOf(array).String()
|
||||
typeName = typeName[strings.LastIndex(typeName, "]")+1:]
|
||||
switch typeName {
|
||||
case "bool", "int", "int32", "int64",
|
||||
"float32", "float64", "string",
|
||||
"uint", "uint32", "uint64":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}()
|
||||
if isValidType {
|
||||
return Value{
|
||||
vtype: ARRAY,
|
||||
array: array,
|
||||
}
|
||||
}
|
||||
}
|
||||
return Value{vtype: INVALID}
|
||||
}
|
||||
|
||||
// Type returns a type of the Value.
|
||||
func (v Value) Type() Type {
|
||||
return v.vtype
|
||||
@@ -183,11 +214,18 @@ func (v Value) AsString() string {
|
||||
return v.stringly
|
||||
}
|
||||
|
||||
// AsArray returns the array Value as an interface{}.
|
||||
func (v Value) AsArray() interface{} {
|
||||
return v.array
|
||||
}
|
||||
|
||||
type unknownValueType struct{}
|
||||
|
||||
// AsInterface returns Value's data as interface{}.
|
||||
func (v Value) AsInterface() interface{} {
|
||||
switch v.Type() {
|
||||
case ARRAY:
|
||||
return v.AsArray()
|
||||
case BOOL:
|
||||
return v.AsBool()
|
||||
case INT32:
|
||||
@@ -211,6 +249,8 @@ func (v Value) AsInterface() interface{} {
|
||||
// Emit returns a string representation of Value's data.
|
||||
func (v Value) Emit() string {
|
||||
switch v.Type() {
|
||||
case ARRAY:
|
||||
return fmt.Sprint(v.array)
|
||||
case BOOL:
|
||||
return strconv.FormatBool(v.AsBool())
|
||||
case INT32:
|
||||
|
@@ -40,6 +40,12 @@ func TestValue(t *testing.T) {
|
||||
wantType: value.BOOL,
|
||||
wantValue: true,
|
||||
},
|
||||
{
|
||||
name: "Key.Array([]bool) correctly return key's internal bool values",
|
||||
value: k.Array([]bool{true, false}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: []bool{true, false},
|
||||
},
|
||||
{
|
||||
name: "Key.Int64() correctly returns keys's internal int64 value",
|
||||
value: k.Int64(42).Value,
|
||||
@@ -94,6 +100,66 @@ func TestValue(t *testing.T) {
|
||||
wantType: bli.unsignedType,
|
||||
wantValue: bli.unsignedValue,
|
||||
},
|
||||
{
|
||||
name: "Key.Array([]int64) correctly returns keys's internal int64 values",
|
||||
value: k.Array([]int64{42, 43}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: []int64{42, 43},
|
||||
},
|
||||
{
|
||||
name: "KeyArray([]uint64) correctly returns keys's internal uint64 values",
|
||||
value: k.Array([]uint64{42, 43}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: []uint64{42, 43},
|
||||
},
|
||||
{
|
||||
name: "Key.Array([]float64) correctly returns keys's internal float64 values",
|
||||
value: k.Array([]float64{42, 43}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: []float64{42, 43},
|
||||
},
|
||||
{
|
||||
name: "Key.Array([]int32) correctly returns keys's internal int32 values",
|
||||
value: k.Array([]int32{42, 43}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: []int32{42, 43},
|
||||
},
|
||||
{
|
||||
name: "Key.Array([]uint32) correctly returns keys's internal uint32 values",
|
||||
value: k.Array([]uint32{42, 43}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: []uint32{42, 43},
|
||||
},
|
||||
{
|
||||
name: "Key.Array([]float32) correctly returns keys's internal float32 values",
|
||||
value: k.Array([]float32{42, 43}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: []float32{42, 43},
|
||||
},
|
||||
{
|
||||
name: "Key.Array([]string) correctly return key's internal string values",
|
||||
value: k.Array([]string{"foo", "bar"}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: []string{"foo", "bar"},
|
||||
},
|
||||
{
|
||||
name: "Key.Array([]int) correctly returns keys's internal signed integral values",
|
||||
value: k.Array([]int{42, 43}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: []int{42, 43},
|
||||
},
|
||||
{
|
||||
name: "Key.Array([]uint) correctly returns keys's internal unsigned integral values",
|
||||
value: k.Array([]uint{42, 43}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: []uint{42, 43},
|
||||
},
|
||||
{
|
||||
name: "Key.Array([][]int) correctly return key's multi dimensional array",
|
||||
value: k.Array([][]int{{1, 2}, {3, 4}}).Value,
|
||||
wantType: value.ARRAY,
|
||||
wantValue: [][]int{{1, 2}, {3, 4}},
|
||||
},
|
||||
} {
|
||||
t.Logf("Running test case %s", testcase.name)
|
||||
if testcase.value.Type() != testcase.wantType {
|
||||
|
@@ -26,6 +26,7 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel/api/global"
|
||||
"go.opentelemetry.io/otel/api/kv"
|
||||
"go.opentelemetry.io/otel/api/kv/value"
|
||||
apitrace "go.opentelemetry.io/otel/api/trace"
|
||||
export "go.opentelemetry.io/otel/sdk/export/trace"
|
||||
"go.opentelemetry.io/otel/sdk/internal"
|
||||
@@ -103,7 +104,10 @@ func (s *span) SetAttributes(attributes ...kv.KeyValue) {
|
||||
}
|
||||
|
||||
func (s *span) SetAttribute(k string, v interface{}) {
|
||||
s.SetAttributes(kv.Infer(k, v))
|
||||
attr := kv.Infer(k, v)
|
||||
if attr.Value.Type() != value.INVALID {
|
||||
s.SetAttributes(attr)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *span) End(options ...apitrace.EndOption) {
|
||||
@@ -293,7 +297,9 @@ func (s *span) copyToCappedAttributes(attributes ...kv.KeyValue) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for _, a := range attributes {
|
||||
s.attributes.add(a)
|
||||
if a.Value.Type() != value.INVALID {
|
||||
s.attributes.add(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user