From 5c4e70278649270e0f1e1f73fd672096be7a3661 Mon Sep 17 00:00:00 2001 From: Anthony J Mirabella Date: Mon, 6 Sep 2021 13:35:45 -0400 Subject: [PATCH] Fix slice-valued attributes when used as map keys Signed-off-by: Anthony J Mirabella --- CHANGELOG.md | 4 + attribute/value.go | 117 +++++++++--------- .../internal/tracetransform/span_test.go | 2 +- 3 files changed, 62 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1db1b8c6333..6c9d86edfdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Fixed + +- Slice-valued attributes can correctly be used as map keys. (#TBD) + ## [1.0.0-RC3] - 2021-09-02 ### Added diff --git a/attribute/value.go b/attribute/value.go index 24c81ea6582..f2c8bdb6453 100644 --- a/attribute/value.go +++ b/attribute/value.go @@ -73,12 +73,7 @@ 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, - } + return sliceValue(v, BOOLSLICE) } // IntValue creates an INT64 Value. @@ -88,14 +83,7 @@ func IntValue(v int) Value { // 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, - } + return sliceValue(v, INT64SLICE) } // Int64Value creates an INT64 Value. @@ -108,12 +96,7 @@ 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, - } + return sliceValue(v, INT64SLICE) } // Float64Value creates a FLOAT64 Value. @@ -126,12 +109,7 @@ 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, - } + return sliceValue(v, FLOAT64SLICE) } // StringValue creates a STRING Value. @@ -144,11 +122,26 @@ 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, + return sliceValue(v, STRINGSLICE) +} + +func sliceValue(v interface{}, vtype Type) Value { + // get array type regardless of dimensions + typ := reflect.TypeOf(v).Elem() + kind := typ.Kind() + switch kind { + case reflect.Bool, reflect.Int, reflect.Int64, + reflect.Float64, reflect.String: + val := reflect.ValueOf(v) + length := val.Len() + frozen := reflect.Indirect(reflect.New(reflect.ArrayOf(length, typ))) + reflect.Copy(frozen, val) + return Value{ + vtype: vtype, + slice: frozen.Interface(), + } + default: + return Value{vtype: INVALID} } } @@ -162,23 +155,7 @@ func StringSliceValue(v []string) Value { func ArrayValue(v interface{}) Value { switch reflect.TypeOf(v).Kind() { case reflect.Array, reflect.Slice: - // get array type regardless of dimensions - typ := reflect.TypeOf(v).Elem() - kind := typ.Kind() - switch kind { - case reflect.Bool, reflect.Int, reflect.Int64, - reflect.Float64, reflect.String: - val := reflect.ValueOf(v) - length := val.Len() - frozen := reflect.Indirect(reflect.New(reflect.ArrayOf(length, typ))) - reflect.Copy(frozen, val) - return Value{ - vtype: ARRAY, - slice: frozen.Interface(), - } - default: - return Value{vtype: INVALID} - } + return sliceValue(v, ARRAY) } return Value{vtype: INVALID} } @@ -197,10 +174,15 @@ func (v Value) AsBool() bool { // 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 + if v.vtype != BOOLSLICE { + return nil } - return nil + r := []bool{} + s := reflect.ValueOf(v.slice) + for i := 0; i < s.Len(); i++ { + r = append(r, s.Index(i).Bool()) + } + return r } // AsInt64 returns the int64 value. Make sure that the Value's type is @@ -212,10 +194,15 @@ func (v Value) AsInt64() int64 { // 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 + if v.vtype != INT64SLICE { + return nil + } + r := []int64{} + s := reflect.ValueOf(v.slice) + for i := 0; i < s.Len(); i++ { + r = append(r, s.Index(i).Int()) } - return nil + return r } // AsFloat64 returns the float64 value. Make sure that the Value's @@ -227,10 +214,15 @@ func (v Value) AsFloat64() float64 { // 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 + if v.vtype != FLOAT64SLICE { + return nil } - return nil + r := []float64{} + s := reflect.ValueOf(v.slice) + for i := 0; i < s.Len(); i++ { + r = append(r, s.Index(i).Float()) + } + return r } // AsString returns the string value. Make sure that the Value's type @@ -242,10 +234,15 @@ func (v Value) AsString() string { // 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 + if v.vtype != STRINGSLICE { + return nil + } + r := []string{} + s := reflect.ValueOf(v.slice) + for i := 0; i < s.Len(); i++ { + r = append(r, s.Index(i).String()) } - return nil + return r } // AsArray returns the array Value as an interface{}. diff --git a/exporters/otlp/otlptrace/internal/tracetransform/span_test.go b/exporters/otlp/otlptrace/internal/tracetransform/span_test.go index 9c772b38c38..e9392c42b38 100644 --- a/exporters/otlp/otlptrace/internal/tracetransform/span_test.go +++ b/exporters/otlp/otlptrace/internal/tracetransform/span_test.go @@ -266,7 +266,7 @@ func TestSpanData(t *testing.T) { DroppedAttributes: 1, DroppedEvents: 2, DroppedLinks: 3, - Resource: resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)), + Resource: resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5), attribute.StringSlice("rk3", []string{"sv1", "sv2"})), InstrumentationLibrary: instrumentation.Library{ Name: "go.opentelemetry.io/test/otel", Version: "v0.0.1",