Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix slice-valued attributes when used as map keys #2223

Merged
merged 4 commits into from Sep 9, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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. (#2223)

## [1.0.0-RC3] - 2021-09-02

### Added
Expand Down
117 changes: 57 additions & 60 deletions attribute/value.go
Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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,
MrAlias marked this conversation as resolved.
Show resolved Hide resolved
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}
}
}

Expand All @@ -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}
}
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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{}.
Expand Down
Expand Up @@ -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",
Expand Down