1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-07-17 01:12:45 +02:00

Deprecate Array attribute in favor of *Slice types (#2162)

* Deprecate Array attribute in favor of *Slice types

* Use new attr types in Jaeger exporter

* Use slice attr types in otlpmetric

* Use slice attr types in otlptrace

* Use slice attr types in zipkin exporter

* Remove array attr test from deprectated oteltest func

* Use StringSlice for cmd arg resource attr

* Add changes to the changelog

* Remove use of deprecated Array func
This commit is contained in:
Tyler Yahn
2021-08-12 08:05:42 -07:00
committed by GitHub
parent df384a9a33
commit 87d09df346
17 changed files with 592 additions and 204 deletions

View File

@ -11,6 +11,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Added ### Added
- Added `ErrorHandlerFunc` to use a function as an `"go.opentelemetry.io/otel".ErrorHandler`. (#2149) - Added `ErrorHandlerFunc` to use a function as an `"go.opentelemetry.io/otel".ErrorHandler`. (#2149)
- Added typed slice attribute types and functionality to the `go.opentelemetry.io/otel/attribute` package to replace the existing array type and functions. (#2162)
- `BoolSlice`, `IntSlice`, `Int64Slice`, `Float64Slice`, and `StringSlice` replace the use of the `Array` function in the package.
### Changed ### Changed
@ -21,6 +23,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- The `go.opentelemetry.io/otel/bridge/opencensus/utils` package is deprecated. - The `go.opentelemetry.io/otel/bridge/opencensus/utils` package is deprecated.
All functionality from this package now exists in the `go.opentelemetry.io/otel/bridge/opencensus` package. All functionality from this package now exists in the `go.opentelemetry.io/otel/bridge/opencensus` package.
The functions from that package should be used instead. (#2166) The functions from that package should be used instead. (#2166)
- The `"go.opentelemetry.io/otel/attribute".Array` function and the related `ARRAY` value type is deprecated.
Use the typed `*Slice` functions and types added to the package instead. (#2162)
### Removed ### Removed

View File

@ -26,10 +26,14 @@ var (
outV attribute.Value outV attribute.Value
outKV attribute.KeyValue outKV attribute.KeyValue
outBool bool outBool bool
outInt64 int64 outBoolSlice []bool
outFloat64 float64 outInt64 int64
outStr string outInt64Slice []int64
outFloat64 float64
outFloat64Slice []float64
outStr string
outStrSlice []string
) )
func benchmarkAny(k string, v interface{}) func(*testing.B) { func benchmarkAny(k string, v interface{}) func(*testing.B) {
@ -91,6 +95,32 @@ func BenchmarkBool(b *testing.B) {
b.Run("Array", benchmarkArray(k, array)) b.Run("Array", benchmarkArray(k, array))
} }
func BenchmarkBoolSlice(b *testing.B) {
k, v := "bool slice", []bool{true, false, true}
kv := attribute.BoolSlice(k, v)
b.Run("Value", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outV = attribute.BoolSliceValue(v)
}
})
b.Run("KeyValue", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outKV = attribute.BoolSlice(k, v)
}
})
b.Run("AsBoolSlice", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outBoolSlice = kv.Value.AsBoolSlice()
}
})
b.Run("Any", benchmarkAny(k, v))
b.Run("Emit", benchmarkEmit(kv))
}
func BenchmarkInt(b *testing.B) { func BenchmarkInt(b *testing.B) {
k, v := "int", int(42) k, v := "int", int(42)
kv := attribute.Int(k, v) kv := attribute.Int(k, v)
@ -113,6 +143,26 @@ func BenchmarkInt(b *testing.B) {
b.Run("Array", benchmarkArray(k, array)) b.Run("Array", benchmarkArray(k, array))
} }
func BenchmarkIntSlice(b *testing.B) {
k, v := "int slice", []int{42, -3, 12}
kv := attribute.IntSlice(k, v)
b.Run("Value", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outV = attribute.IntSliceValue(v)
}
})
b.Run("KeyValue", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outKV = attribute.IntSlice(k, v)
}
})
b.Run("Any", benchmarkAny(k, v))
b.Run("Emit", benchmarkEmit(kv))
}
func BenchmarkInt8(b *testing.B) { func BenchmarkInt8(b *testing.B) {
b.Run("Any", benchmarkAny("int8", int8(42))) b.Run("Any", benchmarkAny("int8", int8(42)))
} }
@ -153,6 +203,32 @@ func BenchmarkInt64(b *testing.B) {
b.Run("Array", benchmarkArray(k, array)) b.Run("Array", benchmarkArray(k, array))
} }
func BenchmarkInt64Slice(b *testing.B) {
k, v := "int64 slice", []int64{42, -3, 12}
kv := attribute.Int64Slice(k, v)
b.Run("Value", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outV = attribute.Int64SliceValue(v)
}
})
b.Run("KeyValue", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outKV = attribute.Int64Slice(k, v)
}
})
b.Run("AsInt64Slice", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outInt64Slice = kv.Value.AsInt64Slice()
}
})
b.Run("Any", benchmarkAny(k, v))
b.Run("Emit", benchmarkEmit(kv))
}
func BenchmarkFloat64(b *testing.B) { func BenchmarkFloat64(b *testing.B) {
k, v := "float64", float64(42) k, v := "float64", float64(42)
kv := attribute.Float64(k, v) kv := attribute.Float64(k, v)
@ -181,6 +257,32 @@ func BenchmarkFloat64(b *testing.B) {
b.Run("Array", benchmarkArray(k, array)) b.Run("Array", benchmarkArray(k, array))
} }
func BenchmarkFloat64Slice(b *testing.B) {
k, v := "float64 slice", []float64{42, -3, 12}
kv := attribute.Float64Slice(k, v)
b.Run("Value", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outV = attribute.Float64SliceValue(v)
}
})
b.Run("KeyValue", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outKV = attribute.Float64Slice(k, v)
}
})
b.Run("AsFloat64Slice", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outFloat64Slice = kv.Value.AsFloat64Slice()
}
})
b.Run("Any", benchmarkAny(k, v))
b.Run("Emit", benchmarkEmit(kv))
}
func BenchmarkString(b *testing.B) { func BenchmarkString(b *testing.B) {
k, v := "string", "42" k, v := "string", "42"
kv := attribute.String(k, v) kv := attribute.String(k, v)
@ -209,12 +311,32 @@ func BenchmarkString(b *testing.B) {
b.Run("Array", benchmarkArray(k, array)) b.Run("Array", benchmarkArray(k, array))
} }
func BenchmarkStringSlice(b *testing.B) {
k, v := "float64 slice", []string{"forty-two", "negative three", "twelve"}
kv := attribute.StringSlice(k, v)
b.Run("Value", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outV = attribute.StringSliceValue(v)
}
})
b.Run("KeyValue", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outKV = attribute.StringSlice(k, v)
}
})
b.Run("AsStringSlice", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
outStrSlice = kv.Value.AsStringSlice()
}
})
b.Run("Any", benchmarkAny(k, v))
b.Run("Emit", benchmarkEmit(kv))
}
func BenchmarkBytes(b *testing.B) { func BenchmarkBytes(b *testing.B) {
b.Run("Any", benchmarkAny("bytes", []byte("bytes"))) b.Run("Any", benchmarkAny("bytes", []byte("bytes")))
} }
type test struct{}
func BenchmarkStruct(b *testing.B) {
b.Run("Any", benchmarkAny("struct", test{}))
}

View File

@ -29,6 +29,17 @@ func (k Key) Bool(v bool) KeyValue {
} }
} }
// BoolSlice creates a KeyValue instance with a BOOLSLICE Value.
//
// If creating both a key and value at the same time, use the provided
// convenience function instead -- BoolSlice(name, value).
func (k Key) BoolSlice(v []bool) KeyValue {
return KeyValue{
Key: k,
Value: BoolSliceValue(v),
}
}
// Int creates a KeyValue instance with an INT64 Value. // Int creates a KeyValue instance with an INT64 Value.
// //
// If creating both a key and value at the same time, use the provided // If creating both a key and value at the same time, use the provided
@ -40,6 +51,17 @@ func (k Key) Int(v int) KeyValue {
} }
} }
// IntSlice creates a KeyValue instance with an INT64SLICE Value.
//
// If creating both a key and value at the same time, use the provided
// convenience function instead -- IntSlice(name, value).
func (k Key) IntSlice(v []int) KeyValue {
return KeyValue{
Key: k,
Value: IntSliceValue(v),
}
}
// Int64 creates a KeyValue instance with an INT64 Value. // Int64 creates a KeyValue instance with an INT64 Value.
// //
// If creating both a key and value at the same time, use the provided // If creating both a key and value at the same time, use the provided
@ -51,6 +73,17 @@ func (k Key) Int64(v int64) KeyValue {
} }
} }
// Int64Slice creates a KeyValue instance with an INT64SLICE Value.
//
// If creating both a key and value at the same time, use the provided
// convenience function instead -- Int64Slice(name, value).
func (k Key) Int64Slice(v []int64) KeyValue {
return KeyValue{
Key: k,
Value: Int64SliceValue(v),
}
}
// Float64 creates a KeyValue instance with a FLOAT64 Value. // Float64 creates a KeyValue instance with a FLOAT64 Value.
// //
// If creating both a key and value at the same time, use the provided // If creating both a key and value at the same time, use the provided
@ -62,6 +95,17 @@ func (k Key) Float64(v float64) KeyValue {
} }
} }
// Float64Slice creates a KeyValue instance with a FLOAT64SLICE Value.
//
// If creating both a key and value at the same time, use the provided
// convenience function instead -- Float64(name, value).
func (k Key) Float64Slice(v []float64) KeyValue {
return KeyValue{
Key: k,
Value: Float64SliceValue(v),
}
}
// String creates a KeyValue instance with a STRING Value. // String creates a KeyValue instance with a STRING Value.
// //
// If creating both a key and value at the same time, use the provided // If creating both a key and value at the same time, use the provided
@ -73,10 +117,23 @@ func (k Key) String(v string) KeyValue {
} }
} }
// StringSlice creates a KeyValue instance with a STRINGSLICE Value.
//
// If creating both a key and value at the same time, use the provided
// convenience function instead -- StringSlice(name, value).
func (k Key) StringSlice(v []string) KeyValue {
return KeyValue{
Key: k,
Value: StringSliceValue(v),
}
}
// Array creates a KeyValue instance with an ARRAY Value. // Array creates a KeyValue instance with an ARRAY Value.
// //
// If creating both a key and value at the same time, use the provided // If creating both a key and value at the same time, use the provided
// convenience function instead -- Array(name, value). // convenience function instead -- Array(name, value).
//
// Deprecated: Use the typed *Slice methods instead.
func (k Key) Array(v interface{}) KeyValue { func (k Key) Array(v interface{}) KeyValue {
return KeyValue{ return KeyValue{
Key: k, Key: k,

View File

@ -36,26 +36,51 @@ func Bool(k string, v bool) KeyValue {
return Key(k).Bool(v) return Key(k).Bool(v)
} }
// BoolSlice creates a KeyValue with a BOOLSLICE Value type.
func BoolSlice(k string, v []bool) KeyValue {
return Key(k).BoolSlice(v)
}
// Int creates a KeyValue with an INT64 Value type. // Int creates a KeyValue with an INT64 Value type.
func Int(k string, v int) KeyValue { func Int(k string, v int) KeyValue {
return Key(k).Int(v) return Key(k).Int(v)
} }
// Int64 creates a KeyValue with a INT64 Value type. // IntSlice creates a KeyValue with an INT64SLICE Value type.
func IntSlice(k string, v []int) KeyValue {
return Key(k).IntSlice(v)
}
// Int64 creates a KeyValue with an INT64 Value type.
func Int64(k string, v int64) KeyValue { func Int64(k string, v int64) KeyValue {
return Key(k).Int64(v) return Key(k).Int64(v)
} }
// Int64Slice creates a KeyValue with an INT64SLICE Value type.
func Int64Slice(k string, v []int64) KeyValue {
return Key(k).Int64Slice(v)
}
// Float64 creates a KeyValue with a FLOAT64 Value type. // Float64 creates a KeyValue with a FLOAT64 Value type.
func Float64(k string, v float64) KeyValue { func Float64(k string, v float64) KeyValue {
return Key(k).Float64(v) return Key(k).Float64(v)
} }
// Float64Slice creates a KeyValue with a FLOAT64SLICE Value type.
func Float64Slice(k string, v []float64) KeyValue {
return Key(k).Float64Slice(v)
}
// String creates a KeyValue with a STRING Value type. // String creates a KeyValue with a STRING Value type.
func String(k, v string) KeyValue { func String(k, v string) KeyValue {
return Key(k).String(v) return Key(k).String(v)
} }
// StringSlice creates a KeyValue with a STRINGSLICE Value type.
func StringSlice(k string, v []string) KeyValue {
return Key(k).StringSlice(v)
}
// Stringer creates a new key-value pair with a passed name and a string // Stringer creates a new key-value pair with a passed name and a string
// value generated by the passed Stringer interface. // value generated by the passed Stringer interface.
func Stringer(k string, v fmt.Stringer) KeyValue { func Stringer(k string, v fmt.Stringer) KeyValue {
@ -64,6 +89,8 @@ func Stringer(k string, v fmt.Stringer) KeyValue {
// Array creates a new key-value pair with a passed name and a array. // Array creates a new key-value pair with a passed name and a array.
// Only arrays of primitive type are supported. // Only arrays of primitive type are supported.
//
// Deprecated: Use the typed *Slice functions instead.
func Array(k string, v interface{}) KeyValue { func Array(k string, v interface{}) KeyValue {
return Key(k).Array(v) return Key(k).Array(v)
} }
@ -82,8 +109,24 @@ func Any(k string, value interface{}) KeyValue {
rv := reflect.ValueOf(value) rv := reflect.ValueOf(value)
switch rv.Kind() { switch rv.Kind() {
case reflect.Array, reflect.Slice: case reflect.Array:
return Array(k, value) rv = rv.Slice(0, rv.Len())
fallthrough
case reflect.Slice:
switch reflect.TypeOf(value).Elem().Kind() {
case reflect.Bool:
return BoolSlice(k, rv.Interface().([]bool))
case reflect.Int:
return IntSlice(k, rv.Interface().([]int))
case reflect.Int64:
return Int64Slice(k, rv.Interface().([]int64))
case reflect.Float64:
return Float64Slice(k, rv.Interface().([]float64))
case reflect.String:
return StringSlice(k, rv.Interface().([]string))
default:
return KeyValue{Key: Key(k), Value: Value{vtype: INVALID}}
}
case reflect.Bool: case reflect.Bool:
return Bool(k, rv.Bool()) return Bool(k, rv.Bool())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:

View File

@ -13,12 +13,16 @@ func _() {
_ = x[INT64-2] _ = x[INT64-2]
_ = x[FLOAT64-3] _ = x[FLOAT64-3]
_ = x[STRING-4] _ = x[STRING-4]
_ = x[ARRAY-5] _ = x[BOOLSLICE-5]
_ = x[INT64SLICE-6]
_ = x[FLOAT64SLICE-7]
_ = x[STRINGSLICE-8]
_ = x[ARRAY-9]
} }
const _Type_name = "INVALIDBOOLINT64FLOAT64STRINGARRAY" const _Type_name = "INVALIDBOOLINT64FLOAT64STRINGBOOLSLICEINT64SLICEFLOAT64SLICESTRINGSLICEARRAY"
var _Type_index = [...]uint8{0, 7, 11, 16, 23, 29, 34} var _Type_index = [...]uint8{0, 7, 11, 16, 23, 29, 38, 48, 60, 71, 76}
func (i Type) String() string { func (i Type) String() string {
if i < 0 || i >= Type(len(_Type_index)-1) { if i < 0 || i >= Type(len(_Type_index)-1) {

View File

@ -33,9 +33,7 @@ type Value struct {
vtype Type vtype Type
numeric uint64 numeric uint64
stringly string stringly string
// TODO Lazy value type? slice interface{}
array interface{}
} }
const ( const (
@ -49,9 +47,19 @@ const (
FLOAT64 FLOAT64
// STRING is a string Type Value. // STRING is a string Type Value.
STRING STRING
// BOOLSLICE is a slice of booleans Type Value.
BOOLSLICE
// INT64SLICE is a slice of 64-bit signed integral numbers Type Value.
INT64SLICE
// FLOAT64SLICE is a slice of 64-bit floating point numbers Type Value.
FLOAT64SLICE
// STRINGSLICE is a slice of strings Type Value.
STRINGSLICE
// ARRAY is an array Type Value used to store 1-dimensional slices or // ARRAY is an array Type Value used to store 1-dimensional slices or
// arrays of bool, int, int32, int64, uint, uint32, uint64, float, // arrays of bool, int, int32, int64, uint, uint32, uint64, float,
// float32, float64, or string types. // float32, float64, or string types.
//
// Deprecated: Use slice types instead.
ARRAY ARRAY
) )
@ -63,11 +71,33 @@ func BoolValue(v bool) Value {
} }
} }
// BoolSliceValue creates a BOOLSLICE Value.
func BoolSliceValue(v []bool) Value {
cp := make([]bool, len(v))
copy(cp, v)
return Value{
vtype: BOOLSLICE,
slice: cp,
}
}
// IntValue creates an INT64 Value. // IntValue creates an INT64 Value.
func IntValue(v int) Value { func IntValue(v int) Value {
return Int64Value(int64(v)) return Int64Value(int64(v))
} }
// IntSliceValue creates an INTSLICE Value.
func IntSliceValue(v []int) Value {
cp := make([]int64, 0, len(v))
for _, i := range v {
cp = append(cp, int64(i))
}
return Value{
vtype: INT64SLICE,
slice: cp,
}
}
// Int64Value creates an INT64 Value. // Int64Value creates an INT64 Value.
func Int64Value(v int64) Value { func Int64Value(v int64) Value {
return Value{ return Value{
@ -76,6 +106,16 @@ func Int64Value(v int64) Value {
} }
} }
// Int64SliceValue creates an INT64SLICE Value.
func Int64SliceValue(v []int64) Value {
cp := make([]int64, len(v))
copy(cp, v)
return Value{
vtype: INT64SLICE,
slice: cp,
}
}
// Float64Value creates a FLOAT64 Value. // Float64Value creates a FLOAT64 Value.
func Float64Value(v float64) Value { func Float64Value(v float64) Value {
return Value{ return Value{
@ -84,6 +124,16 @@ func Float64Value(v float64) Value {
} }
} }
// Float64SliceValue creates a FLOAT64SLICE Value.
func Float64SliceValue(v []float64) Value {
cp := make([]float64, len(v))
copy(cp, v)
return Value{
vtype: FLOAT64SLICE,
slice: cp,
}
}
// StringValue creates a STRING Value. // StringValue creates a STRING Value.
func StringValue(v string) Value { func StringValue(v string) Value {
return Value{ return Value{
@ -92,11 +142,23 @@ func StringValue(v string) Value {
} }
} }
// StringSliceValue creates a STRINGSLICE Value.
func StringSliceValue(v []string) Value {
cp := make([]string, len(v))
copy(cp, v)
return Value{
vtype: STRINGSLICE,
slice: cp,
}
}
// ArrayValue creates an ARRAY value from an array or slice. // ArrayValue creates an ARRAY value from an array or slice.
// Only arrays or slices of bool, int, int64, float, float64, or string types are allowed. // Only arrays or slices of bool, int, int64, float, float64, or string types are allowed.
// Specifically, arrays and slices can not contain other arrays, slices, structs, or non-standard // Specifically, arrays and slices can not contain other arrays, slices, structs, or non-standard
// types. If the passed value is not an array or slice of these types an // types. If the passed value is not an array or slice of these types an
// INVALID value is returned. // INVALID value is returned.
//
// Deprecated: Use the typed *SliceValue functions instead.
func ArrayValue(v interface{}) Value { func ArrayValue(v interface{}) Value {
switch reflect.TypeOf(v).Kind() { switch reflect.TypeOf(v).Kind() {
case reflect.Array, reflect.Slice: case reflect.Array, reflect.Slice:
@ -112,7 +174,7 @@ func ArrayValue(v interface{}) Value {
reflect.Copy(frozen, val) reflect.Copy(frozen, val)
return Value{ return Value{
vtype: ARRAY, vtype: ARRAY,
array: frozen.Interface(), slice: frozen.Interface(),
} }
default: default:
return Value{vtype: INVALID} return Value{vtype: INVALID}
@ -132,27 +194,65 @@ func (v Value) AsBool() bool {
return internal.RawToBool(v.numeric) return internal.RawToBool(v.numeric)
} }
// AsBoolSlice returns the []bool value. Make sure that the Value's type is
// BOOLSLICE.
func (v Value) AsBoolSlice() []bool {
if s, ok := v.slice.([]bool); ok {
return s
}
return nil
}
// AsInt64 returns the int64 value. Make sure that the Value's type is // AsInt64 returns the int64 value. Make sure that the Value's type is
// INT64. // INT64.
func (v Value) AsInt64() int64 { func (v Value) AsInt64() int64 {
return internal.RawToInt64(v.numeric) return internal.RawToInt64(v.numeric)
} }
// AsInt64Slice returns the []int64 value. Make sure that the Value's type is
// INT64SLICE.
func (v Value) AsInt64Slice() []int64 {
if s, ok := v.slice.([]int64); ok {
return s
}
return nil
}
// AsFloat64 returns the float64 value. Make sure that the Value's // AsFloat64 returns the float64 value. Make sure that the Value's
// type is FLOAT64. // type is FLOAT64.
func (v Value) AsFloat64() float64 { func (v Value) AsFloat64() float64 {
return internal.RawToFloat64(v.numeric) return internal.RawToFloat64(v.numeric)
} }
// AsFloat64Slice returns the []float64 value. Make sure that the Value's type is
// INT64SLICE.
func (v Value) AsFloat64Slice() []float64 {
if s, ok := v.slice.([]float64); ok {
return s
}
return nil
}
// AsString returns the string value. Make sure that the Value's type // AsString returns the string value. Make sure that the Value's type
// is STRING. // is STRING.
func (v Value) AsString() string { func (v Value) AsString() string {
return v.stringly return v.stringly
} }
// AsStringSlice returns the []string value. Make sure that the Value's type is
// INT64SLICE.
func (v Value) AsStringSlice() []string {
if s, ok := v.slice.([]string); ok {
return s
}
return nil
}
// AsArray returns the array Value as an interface{}. // AsArray returns the array Value as an interface{}.
//
// Deprecated: Use the typed As*Slice functions instead.
func (v Value) AsArray() interface{} { func (v Value) AsArray() interface{} {
return v.array return v.slice
} }
type unknownValueType struct{} type unknownValueType struct{}
@ -164,12 +264,20 @@ func (v Value) AsInterface() interface{} {
return v.AsArray() return v.AsArray()
case BOOL: case BOOL:
return v.AsBool() return v.AsBool()
case BOOLSLICE:
return v.AsBoolSlice()
case INT64: case INT64:
return v.AsInt64() return v.AsInt64()
case INT64SLICE:
return v.AsInt64Slice()
case FLOAT64: case FLOAT64:
return v.AsFloat64() return v.AsFloat64()
case FLOAT64SLICE:
return v.AsFloat64Slice()
case STRING: case STRING:
return v.stringly return v.stringly
case STRINGSLICE:
return v.AsStringSlice()
} }
return unknownValueType{} return unknownValueType{}
} }
@ -177,8 +285,8 @@ func (v Value) AsInterface() interface{} {
// Emit returns a string representation of Value's data. // Emit returns a string representation of Value's data.
func (v Value) Emit() string { func (v Value) Emit() string {
switch v.Type() { switch v.Type() {
case ARRAY: case ARRAY, BOOLSLICE, INT64SLICE, FLOAT64SLICE, STRINGSLICE:
return fmt.Sprint(v.array) return fmt.Sprint(v.slice)
case BOOL: case BOOL:
return strconv.FormatBool(v.AsBool()) return strconv.FormatBool(v.AsBool())
case INT64: case INT64:

View File

@ -25,7 +25,6 @@ import (
func TestValue(t *testing.T) { func TestValue(t *testing.T) {
k := attribute.Key("test") k := attribute.Key("test")
bli := getBitlessInfo(42)
for _, testcase := range []struct { for _, testcase := range []struct {
name string name string
value attribute.Value value attribute.Value
@ -38,6 +37,12 @@ func TestValue(t *testing.T) {
wantType: attribute.BOOL, wantType: attribute.BOOL,
wantValue: true, wantValue: true,
}, },
{
name: "Key.BoolSlice() correctly returns keys's internal []bool value",
value: k.BoolSlice([]bool{true, false, true}).Value,
wantType: attribute.BOOLSLICE,
wantValue: []bool{true, false, true},
},
{ {
name: "Key.Array([]bool) correctly return key's internal bool values", name: "Key.Array([]bool) correctly return key's internal bool values",
value: k.Array([]bool{true, false}).Value, value: k.Array([]bool{true, false}).Value,
@ -51,22 +56,10 @@ func TestValue(t *testing.T) {
wantValue: int64(42), wantValue: int64(42),
}, },
{ {
name: "Key.Float64() correctly returns keys's internal float64 value", name: "Key.Int64Slice() correctly returns keys's internal []int64 value",
value: k.Float64(42.1).Value, value: k.Int64Slice([]int64{42, -3, 12}).Value,
wantType: attribute.FLOAT64, wantType: attribute.INT64SLICE,
wantValue: 42.1, wantValue: []int64{42, -3, 12},
},
{
name: "Key.String() correctly returns keys's internal string value",
value: k.String("foo").Value,
wantType: attribute.STRING,
wantValue: "foo",
},
{
name: "Key.Int() correctly returns keys's internal signed integral value",
value: k.Int(bli.intValue).Value,
wantType: bli.signedType,
wantValue: bli.signedValue,
}, },
{ {
name: "Key.Array([]int64) correctly returns keys's internal int64 values", name: "Key.Array([]int64) correctly returns keys's internal int64 values",
@ -75,16 +68,16 @@ func TestValue(t *testing.T) {
wantValue: [2]int64{42, 43}, wantValue: [2]int64{42, 43},
}, },
{ {
name: "Key.Array([]float64) correctly returns keys's internal float64 values", name: "Key.Int() correctly returns keys's internal signed integral value",
value: k.Array([]float64{42, 43}).Value, value: k.Int(42).Value,
wantType: attribute.ARRAY, wantType: attribute.INT64,
wantValue: [2]float64{42, 43}, wantValue: int64(42),
}, },
{ {
name: "Key.Array([]string) correctly return key's internal string values", name: "Key.IntSlice() correctly returns keys's internal []int64 value",
value: k.Array([]string{"foo", "bar"}).Value, value: k.IntSlice([]int{42, -3, 12}).Value,
wantType: attribute.ARRAY, wantType: attribute.INT64SLICE,
wantValue: [2]string{"foo", "bar"}, wantValue: []int64{42, -3, 12},
}, },
{ {
name: "Key.Array([]int) correctly returns keys's internal signed integral values", name: "Key.Array([]int) correctly returns keys's internal signed integral values",
@ -92,6 +85,42 @@ func TestValue(t *testing.T) {
wantType: attribute.ARRAY, wantType: attribute.ARRAY,
wantValue: [2]int{42, 43}, wantValue: [2]int{42, 43},
}, },
{
name: "Key.Float64() correctly returns keys's internal float64 value",
value: k.Float64(42.1).Value,
wantType: attribute.FLOAT64,
wantValue: 42.1,
},
{
name: "Key.Float64Slice() correctly returns keys's internal []float64 value",
value: k.Float64Slice([]float64{42, -3, 12}).Value,
wantType: attribute.FLOAT64SLICE,
wantValue: []float64{42, -3, 12},
},
{
name: "Key.Array([]float64) correctly returns keys's internal float64 values",
value: k.Array([]float64{42, 43}).Value,
wantType: attribute.ARRAY,
wantValue: [2]float64{42, 43},
},
{
name: "Key.String() correctly returns keys's internal string value",
value: k.String("foo").Value,
wantType: attribute.STRING,
wantValue: "foo",
},
{
name: "Key.StringSlice() correctly returns keys's internal []string value",
value: k.StringSlice([]string{"forty-two", "negative three", "twelve"}).Value,
wantType: attribute.STRINGSLICE,
wantValue: []string{"forty-two", "negative three", "twelve"},
},
{
name: "Key.Array([]string) correctly return key's internal string values",
value: k.Array([]string{"foo", "bar"}).Value,
wantType: attribute.ARRAY,
wantValue: [2]string{"foo", "bar"},
},
{ {
name: "Key.Array([][]int) refuses to create multi-dimensional array", name: "Key.Array([][]int) refuses to create multi-dimensional array",
value: k.Array([][]int{{1, 2}, {3, 4}}).Value, value: k.Array([][]int{{1, 2}, {3, 4}}).Value,
@ -113,22 +142,6 @@ func TestValue(t *testing.T) {
} }
} }
type bitlessInfo struct {
intValue int
uintValue uint
signedType attribute.Type
signedValue interface{}
}
func getBitlessInfo(i int) bitlessInfo {
return bitlessInfo{
intValue: i,
uintValue: uint(i),
signedType: attribute.INT64,
signedValue: int64(i),
}
}
func TestAsArrayValue(t *testing.T) { func TestAsArrayValue(t *testing.T) {
v := attribute.ArrayValue([]int{1, 2, 3}).AsArray() v := attribute.ArrayValue([]int{1, 2, 3}).AsArray()
// Ensure the returned dynamic type is stable. // Ensure the returned dynamic type is stable.

View File

@ -248,8 +248,11 @@ func keyValueToTag(keyValue attribute.KeyValue) *gen.Tag {
VDouble: &f, VDouble: &f,
VType: gen.TagType_DOUBLE, VType: gen.TagType_DOUBLE,
} }
case attribute.ARRAY: case attribute.BOOLSLICE,
json, _ := json.Marshal(keyValue.Value.AsArray()) attribute.INT64SLICE,
attribute.FLOAT64SLICE,
attribute.STRINGSLICE:
json, _ := json.Marshal(keyValue.Value.AsInterface())
a := (string)(json) a := (string)(json)
tag = &gen.Tag{ tag = &gen.Tag{
Key: string(keyValue.Key), Key: string(keyValue.Key),

View File

@ -323,7 +323,7 @@ func Test_spanSnapshotToThrift(t *testing.T) {
StartTime: now, StartTime: now,
EndTime: now, EndTime: now,
Attributes: []attribute.KeyValue{ Attributes: []attribute.KeyValue{
attribute.Array("arr", []int{0, 1, 2, 3}), attribute.IntSlice("arr", []int{0, 1, 2, 3}),
}, },
Status: sdktrace.Status{ Status: sdktrace.Status{
Code: codes.Unset, Code: codes.Unset,

View File

@ -15,8 +15,6 @@
package metrictransform package metrictransform
import ( import (
"reflect"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
commonpb "go.opentelemetry.io/proto/otlp/common/v1" commonpb "go.opentelemetry.io/proto/otlp/common/v1"
@ -68,22 +66,40 @@ func Value(v attribute.Value) *commonpb.AnyValue {
av.Value = &commonpb.AnyValue_BoolValue{ av.Value = &commonpb.AnyValue_BoolValue{
BoolValue: v.AsBool(), BoolValue: v.AsBool(),
} }
case attribute.BOOLSLICE:
av.Value = &commonpb.AnyValue_ArrayValue{
ArrayValue: &commonpb.ArrayValue{
Values: boolSliceValues(v.AsBoolSlice()),
},
}
case attribute.INT64: case attribute.INT64:
av.Value = &commonpb.AnyValue_IntValue{ av.Value = &commonpb.AnyValue_IntValue{
IntValue: v.AsInt64(), IntValue: v.AsInt64(),
} }
case attribute.INT64SLICE:
av.Value = &commonpb.AnyValue_ArrayValue{
ArrayValue: &commonpb.ArrayValue{
Values: int64SliceValues(v.AsInt64Slice()),
},
}
case attribute.FLOAT64: case attribute.FLOAT64:
av.Value = &commonpb.AnyValue_DoubleValue{ av.Value = &commonpb.AnyValue_DoubleValue{
DoubleValue: v.AsFloat64(), DoubleValue: v.AsFloat64(),
} }
case attribute.FLOAT64SLICE:
av.Value = &commonpb.AnyValue_ArrayValue{
ArrayValue: &commonpb.ArrayValue{
Values: float64SliceValues(v.AsFloat64Slice()),
},
}
case attribute.STRING: case attribute.STRING:
av.Value = &commonpb.AnyValue_StringValue{ av.Value = &commonpb.AnyValue_StringValue{
StringValue: v.AsString(), StringValue: v.AsString(),
} }
case attribute.ARRAY: case attribute.STRINGSLICE:
av.Value = &commonpb.AnyValue_ArrayValue{ av.Value = &commonpb.AnyValue_ArrayValue{
ArrayValue: &commonpb.ArrayValue{ ArrayValue: &commonpb.ArrayValue{
Values: arrayValues(v), Values: stringSliceValues(v.AsStringSlice()),
}, },
} }
default: default:
@ -94,56 +110,50 @@ func Value(v attribute.Value) *commonpb.AnyValue {
return av return av
} }
func arrayValues(v attribute.Value) []*commonpb.AnyValue { func boolSliceValues(vals []bool) []*commonpb.AnyValue {
a := v.AsArray() converted := make([]*commonpb.AnyValue, len(vals))
aType := reflect.TypeOf(a) for i, v := range vals {
var valueFunc func(reflect.Value) *commonpb.AnyValue converted[i] = &commonpb.AnyValue{
switch aType.Elem().Kind() { Value: &commonpb.AnyValue_BoolValue{
case reflect.Bool: BoolValue: v,
valueFunc = func(v reflect.Value) *commonpb.AnyValue { },
return &commonpb.AnyValue{
Value: &commonpb.AnyValue_BoolValue{
BoolValue: v.Bool(),
},
}
}
case reflect.Int, reflect.Int64:
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
return &commonpb.AnyValue{
Value: &commonpb.AnyValue_IntValue{
IntValue: v.Int(),
},
}
}
case reflect.Uintptr:
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
return &commonpb.AnyValue{
Value: &commonpb.AnyValue_IntValue{
IntValue: int64(v.Uint()),
},
}
}
case reflect.Float64:
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
return &commonpb.AnyValue{
Value: &commonpb.AnyValue_DoubleValue{
DoubleValue: v.Float(),
},
}
}
case reflect.String:
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
return &commonpb.AnyValue{
Value: &commonpb.AnyValue_StringValue{
StringValue: v.String(),
},
}
} }
} }
return converted
results := make([]*commonpb.AnyValue, aType.Len()) }
for i, aValue := 0, reflect.ValueOf(a); i < aValue.Len(); i++ {
results[i] = valueFunc(aValue.Index(i)) func int64SliceValues(vals []int64) []*commonpb.AnyValue {
} converted := make([]*commonpb.AnyValue, len(vals))
return results for i, v := range vals {
converted[i] = &commonpb.AnyValue{
Value: &commonpb.AnyValue_IntValue{
IntValue: v,
},
}
}
return converted
}
func float64SliceValues(vals []float64) []*commonpb.AnyValue {
converted := make([]*commonpb.AnyValue, len(vals))
for i, v := range vals {
converted[i] = &commonpb.AnyValue{
Value: &commonpb.AnyValue_DoubleValue{
DoubleValue: v,
},
}
}
return converted
}
func stringSliceValues(vals []string) []*commonpb.AnyValue {
converted := make([]*commonpb.AnyValue, len(vals))
for i, v := range vals {
converted[i] = &commonpb.AnyValue{
Value: &commonpb.AnyValue_StringValue{
StringValue: v,
},
}
}
return converted
} }

View File

@ -112,7 +112,10 @@ func TestArrayAttributes(t *testing.T) {
{nil, nil}, {nil, nil},
{ {
[]attribute.KeyValue{ []attribute.KeyValue{
attribute.Array("invalid", [][]string{{"1", "2"}, {"a"}}), {
Key: attribute.Key("invalid"),
Value: attribute.Value{},
},
}, },
[]*commonpb.KeyValue{ []*commonpb.KeyValue{
{ {
@ -127,18 +130,18 @@ func TestArrayAttributes(t *testing.T) {
}, },
{ {
[]attribute.KeyValue{ []attribute.KeyValue{
attribute.Array("bool array to bool array", []bool{true, false}), attribute.BoolSlice("bool slice to bool array", []bool{true, false}),
attribute.Array("int array to int64 array", []int{1, 2, 3}), attribute.IntSlice("int slice to int64 array", []int{1, 2, 3}),
attribute.Array("int64 array to int64 array", []int64{1, 2, 3}), attribute.Int64Slice("int64 slice to int64 array", []int64{1, 2, 3}),
attribute.Array("float64 array to double array", []float64{1.11, 2.22, 3.33}), attribute.Float64Slice("float64 slice to double array", []float64{1.11, 2.22, 3.33}),
attribute.Array("string array to string array", []string{"foo", "bar", "baz"}), attribute.StringSlice("string slice to string array", []string{"foo", "bar", "baz"}),
}, },
[]*commonpb.KeyValue{ []*commonpb.KeyValue{
newOTelBoolArray("bool array to bool array", []bool{true, false}), newOTelBoolArray("bool slice to bool array", []bool{true, false}),
newOTelIntArray("int array to int64 array", []int64{1, 2, 3}), newOTelIntArray("int slice to int64 array", []int64{1, 2, 3}),
newOTelIntArray("int64 array to int64 array", []int64{1, 2, 3}), newOTelIntArray("int64 slice to int64 array", []int64{1, 2, 3}),
newOTelDoubleArray("float64 array to double array", []float64{1.11, 2.22, 3.33}), newOTelDoubleArray("float64 slice to double array", []float64{1.11, 2.22, 3.33}),
newOTelStringArray("string array to string array", []string{"foo", "bar", "baz"}), newOTelStringArray("string slice to string array", []string{"foo", "bar", "baz"}),
}, },
}, },
} { } {

View File

@ -15,8 +15,6 @@
package tracetransform package tracetransform
import ( import (
"reflect"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
commonpb "go.opentelemetry.io/proto/otlp/common/v1" commonpb "go.opentelemetry.io/proto/otlp/common/v1"
@ -68,22 +66,40 @@ func Value(v attribute.Value) *commonpb.AnyValue {
av.Value = &commonpb.AnyValue_BoolValue{ av.Value = &commonpb.AnyValue_BoolValue{
BoolValue: v.AsBool(), BoolValue: v.AsBool(),
} }
case attribute.BOOLSLICE:
av.Value = &commonpb.AnyValue_ArrayValue{
ArrayValue: &commonpb.ArrayValue{
Values: boolSliceValues(v.AsBoolSlice()),
},
}
case attribute.INT64: case attribute.INT64:
av.Value = &commonpb.AnyValue_IntValue{ av.Value = &commonpb.AnyValue_IntValue{
IntValue: v.AsInt64(), IntValue: v.AsInt64(),
} }
case attribute.INT64SLICE:
av.Value = &commonpb.AnyValue_ArrayValue{
ArrayValue: &commonpb.ArrayValue{
Values: int64SliceValues(v.AsInt64Slice()),
},
}
case attribute.FLOAT64: case attribute.FLOAT64:
av.Value = &commonpb.AnyValue_DoubleValue{ av.Value = &commonpb.AnyValue_DoubleValue{
DoubleValue: v.AsFloat64(), DoubleValue: v.AsFloat64(),
} }
case attribute.FLOAT64SLICE:
av.Value = &commonpb.AnyValue_ArrayValue{
ArrayValue: &commonpb.ArrayValue{
Values: float64SliceValues(v.AsFloat64Slice()),
},
}
case attribute.STRING: case attribute.STRING:
av.Value = &commonpb.AnyValue_StringValue{ av.Value = &commonpb.AnyValue_StringValue{
StringValue: v.AsString(), StringValue: v.AsString(),
} }
case attribute.ARRAY: case attribute.STRINGSLICE:
av.Value = &commonpb.AnyValue_ArrayValue{ av.Value = &commonpb.AnyValue_ArrayValue{
ArrayValue: &commonpb.ArrayValue{ ArrayValue: &commonpb.ArrayValue{
Values: arrayValues(v), Values: stringSliceValues(v.AsStringSlice()),
}, },
} }
default: default:
@ -94,56 +110,50 @@ func Value(v attribute.Value) *commonpb.AnyValue {
return av return av
} }
func arrayValues(v attribute.Value) []*commonpb.AnyValue { func boolSliceValues(vals []bool) []*commonpb.AnyValue {
a := v.AsArray() converted := make([]*commonpb.AnyValue, len(vals))
aType := reflect.TypeOf(a) for i, v := range vals {
var valueFunc func(reflect.Value) *commonpb.AnyValue converted[i] = &commonpb.AnyValue{
switch aType.Elem().Kind() { Value: &commonpb.AnyValue_BoolValue{
case reflect.Bool: BoolValue: v,
valueFunc = func(v reflect.Value) *commonpb.AnyValue { },
return &commonpb.AnyValue{
Value: &commonpb.AnyValue_BoolValue{
BoolValue: v.Bool(),
},
}
}
case reflect.Int, reflect.Int64:
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
return &commonpb.AnyValue{
Value: &commonpb.AnyValue_IntValue{
IntValue: v.Int(),
},
}
}
case reflect.Uintptr:
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
return &commonpb.AnyValue{
Value: &commonpb.AnyValue_IntValue{
IntValue: int64(v.Uint()),
},
}
}
case reflect.Float64:
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
return &commonpb.AnyValue{
Value: &commonpb.AnyValue_DoubleValue{
DoubleValue: v.Float(),
},
}
}
case reflect.String:
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
return &commonpb.AnyValue{
Value: &commonpb.AnyValue_StringValue{
StringValue: v.String(),
},
}
} }
} }
return converted
results := make([]*commonpb.AnyValue, aType.Len()) }
for i, aValue := 0, reflect.ValueOf(a); i < aValue.Len(); i++ {
results[i] = valueFunc(aValue.Index(i)) func int64SliceValues(vals []int64) []*commonpb.AnyValue {
} converted := make([]*commonpb.AnyValue, len(vals))
return results for i, v := range vals {
converted[i] = &commonpb.AnyValue{
Value: &commonpb.AnyValue_IntValue{
IntValue: v,
},
}
}
return converted
}
func float64SliceValues(vals []float64) []*commonpb.AnyValue {
converted := make([]*commonpb.AnyValue, len(vals))
for i, v := range vals {
converted[i] = &commonpb.AnyValue{
Value: &commonpb.AnyValue_DoubleValue{
DoubleValue: v,
},
}
}
return converted
}
func stringSliceValues(vals []string) []*commonpb.AnyValue {
converted := make([]*commonpb.AnyValue, len(vals))
for i, v := range vals {
converted[i] = &commonpb.AnyValue{
Value: &commonpb.AnyValue_StringValue{
StringValue: v,
},
}
}
return converted
} }

View File

@ -112,7 +112,10 @@ func TestArrayAttributes(t *testing.T) {
{nil, nil}, {nil, nil},
{ {
[]attribute.KeyValue{ []attribute.KeyValue{
attribute.Array("invalid", [][]string{{"1", "2"}, {"a"}}), {
Key: attribute.Key("invalid"),
Value: attribute.Value{},
},
}, },
[]*commonpb.KeyValue{ []*commonpb.KeyValue{
{ {
@ -127,18 +130,18 @@ func TestArrayAttributes(t *testing.T) {
}, },
{ {
[]attribute.KeyValue{ []attribute.KeyValue{
attribute.Array("bool array to bool array", []bool{true, false}), attribute.BoolSlice("bool slice to bool array", []bool{true, false}),
attribute.Array("int array to int64 array", []int{1, 2, 3}), attribute.IntSlice("int slice to int64 array", []int{1, 2, 3}),
attribute.Array("int64 array to int64 array", []int64{1, 2, 3}), attribute.Int64Slice("int64 slice to int64 array", []int64{1, 2, 3}),
attribute.Array("float64 array to double array", []float64{1.11, 2.22, 3.33}), attribute.Float64Slice("float64 slice to double array", []float64{1.11, 2.22, 3.33}),
attribute.Array("string array to string array", []string{"foo", "bar", "baz"}), attribute.StringSlice("string slice to string array", []string{"foo", "bar", "baz"}),
}, },
[]*commonpb.KeyValue{ []*commonpb.KeyValue{
newOTelBoolArray("bool array to bool array", []bool{true, false}), newOTelBoolArray("bool slice to bool array", []bool{true, false}),
newOTelIntArray("int array to int64 array", []int64{1, 2, 3}), newOTelIntArray("int slice to int64 array", []int64{1, 2, 3}),
newOTelIntArray("int64 array to int64 array", []int64{1, 2, 3}), newOTelIntArray("int64 slice to int64 array", []int64{1, 2, 3}),
newOTelDoubleArray("float64 array to double array", []float64{1.11, 2.22, 3.33}), newOTelDoubleArray("float64 slice to double array", []float64{1.11, 2.22, 3.33}),
newOTelStringArray("string array to string array", []string{"foo", "bar", "baz"}), newOTelStringArray("string slice to string array", []string{"foo", "bar", "baz"}),
}, },
}, },
} { } {

View File

@ -181,9 +181,18 @@ func toZipkinTags(data tracesdk.ReadOnlySpan) map[string]string {
m := make(map[string]string, len(attr)+len(extraZipkinTags)) m := make(map[string]string, len(attr)+len(extraZipkinTags))
for _, kv := range attr { for _, kv := range attr {
switch kv.Value.Type() { switch kv.Value.Type() {
// For array attributes, serialize as JSON list string. // For slice attributes, serialize as JSON list string.
case attribute.ARRAY: case attribute.BOOLSLICE:
json, _ := json.Marshal(kv.Value.AsArray()) json, _ := json.Marshal(kv.Value.AsBoolSlice())
m[(string)(kv.Key)] = (string)(json)
case attribute.INT64SLICE:
json, _ := json.Marshal(kv.Value.AsInt64Slice())
m[(string)(kv.Key)] = (string)(json)
case attribute.FLOAT64SLICE:
json, _ := json.Marshal(kv.Value.AsFloat64Slice())
m[(string)(kv.Key)] = (string)(json)
case attribute.STRINGSLICE:
json, _ := json.Marshal(kv.Value.AsStringSlice())
m[(string)(kv.Key)] = (string)(json) m[(string)(kv.Key)] = (string)(json)
default: default:
m[(string)(kv.Key)] = kv.Value.Emit() m[(string)(kv.Key)] = kv.Value.Emit()

View File

@ -59,7 +59,7 @@ func TestModelConversion(t *testing.T) {
Attributes: []attribute.KeyValue{ Attributes: []attribute.KeyValue{
attribute.Int64("attr1", 42), attribute.Int64("attr1", 42),
attribute.String("attr2", "bar"), attribute.String("attr2", "bar"),
attribute.Array("attr3", []int{0, 1, 2}), attribute.IntSlice("attr3", []int{0, 1, 2}),
}, },
Events: []tracesdk.Event{ Events: []tracesdk.Event{
{ {

View File

@ -33,9 +33,8 @@ func TestTraceStateFromKeyValues(t *testing.T) {
attribute.Bool("key1", true), attribute.Bool("key1", true),
attribute.Int64("key2", 1), attribute.Int64("key2", 1),
attribute.Float64("key3", 1.1), attribute.Float64("key3", 1.1),
attribute.Array("key4", []int{1, 1}),
) )
require.NoError(t, err) require.NoError(t, err)
expected := "key0=string,key1=true,key2=1,key3=1.1,key4=[1 1]" expected := "key0=string,key1=true,key2=1,key3=1.1"
assert.Equal(t, expected, ts.String()) assert.Equal(t, expected, ts.String())
} }

View File

@ -138,7 +138,7 @@ func (processExecutablePathDetector) Detect(ctx context.Context) (*Resource, err
// Detect returns a *Resource that describes all the command arguments as received // Detect returns a *Resource that describes all the command arguments as received
// by the process. // by the process.
func (processCommandArgsDetector) Detect(ctx context.Context) (*Resource, error) { func (processCommandArgsDetector) Detect(ctx context.Context) (*Resource, error) {
return NewWithAttributes(semconv.SchemaURL, semconv.ProcessCommandArgsKey.Array(commandArgs())), nil return NewWithAttributes(semconv.SchemaURL, semconv.ProcessCommandArgsKey.StringSlice(commandArgs())), nil
} }
// Detect returns a *Resource that describes the username of the user that owns the // Detect returns a *Resource that describes the username of the user that owns the