diff --git a/internal/testdata/common.go b/internal/testdata/common.go index 1d611938a0d9..73b454ae7ce5 100644 --- a/internal/testdata/common.go +++ b/internal/testdata/common.go @@ -19,12 +19,12 @@ import ( ) var ( - resourceAttributes1 = pdata.NewMapFromRaw(map[string]pdata.Value{"resource-attr": pdata.NewValueString("resource-attr-val-1")}) - resourceAttributes2 = pdata.NewMapFromRaw(map[string]pdata.Value{"resource-attr": pdata.NewValueString("resource-attr-val-2")}) - spanEventAttributes = pdata.NewMapFromRaw(map[string]pdata.Value{"span-event-attr": pdata.NewValueString("span-event-attr-val")}) - spanLinkAttributes = pdata.NewMapFromRaw(map[string]pdata.Value{"span-link-attr": pdata.NewValueString("span-link-attr-val")}) - spanAttributes = pdata.NewMapFromRaw(map[string]pdata.Value{"span-attr": pdata.NewValueString("span-attr-val")}) - metricAttachment = pdata.NewMapFromRaw(map[string]pdata.Value{"exemplar-attachment": pdata.NewValueString("exemplar-attachment-value")}) + resourceAttributes1 = pdata.NewMapFromRaw(map[string]interface{}{"resource-attr": "resource-attr-val-1"}) + resourceAttributes2 = pdata.NewMapFromRaw(map[string]interface{}{"resource-attr": "resource-attr-val-2"}) + spanEventAttributes = pdata.NewMapFromRaw(map[string]interface{}{"span-event-attr": "span-event-attr-val"}) + spanLinkAttributes = pdata.NewMapFromRaw(map[string]interface{}{"span-link-attr": "span-link-attr-val"}) + spanAttributes = pdata.NewMapFromRaw(map[string]interface{}{"span-attr": "span-attr-val"}) + metricAttachment = pdata.NewMapFromRaw(map[string]interface{}{"exemplar-attachment": "exemplar-attachment-value"}) ) const ( diff --git a/model/internal/pdata/common.go b/model/internal/pdata/common.go index 9ea7ea99dce1..82720c16c35d 100644 --- a/model/internal/pdata/common.go +++ b/model/internal/pdata/common.go @@ -132,6 +132,65 @@ func NewValueBytes(v []byte) Value { return Value{orig: &otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_BytesValue{BytesValue: v}}} } +func newValueFromRaw(iv interface{}) Value { + switch tv := iv.(type) { + case nil: + return NewValueEmpty() + case string: + return NewValueString(tv) + case int: + return NewValueInt(int64(tv)) + case int8: + return NewValueInt(int64(tv)) + case int16: + return NewValueInt(int64(tv)) + case int32: + return NewValueInt(int64(tv)) + case int64: + return NewValueInt(tv) + case uint: + return NewValueInt(int64(tv)) + case uint8: + return NewValueInt(int64(tv)) + case uint16: + return NewValueInt(int64(tv)) + case uint32: + return NewValueInt(int64(tv)) + case uint64: + return NewValueInt(int64(tv)) + case float32: + return NewValueDouble(float64(tv)) + case float64: + return NewValueDouble(tv) + case bool: + return NewValueBool(tv) + case []byte: + return NewValueBytes(tv) + case Map: + mv := NewValueMap() + mv.MapVal().EnsureCapacity(tv.Len()) + tv.CopyTo(mv.MapVal()) + return mv + case map[string]interface{}: + mv := NewValueMap() + mv.MapVal().EnsureCapacity(len(tv)) + NewMapFromRaw(tv).CopyTo(mv.MapVal()) + return mv + case Slice: + av := NewValueArray() + av.SliceVal().EnsureCapacity(tv.Len()) + tv.CopyTo(av.SliceVal()) + return av + case []interface{}: + av := NewValueArray() + av.SliceVal().EnsureCapacity(len(tv)) + newSliceFromRaw(tv).CopyTo(av.SliceVal()) + return av + default: + return NewValueString(fmt.Sprintf("", tv)) + } +} + // Type returns the type of the value for this Value. // Calling this function on zero-initialized Value will cause a panic. func (v Value) Type() ValueType { @@ -432,6 +491,28 @@ func float64AsString(f float64) string { return string(b) } +func (v Value) asRaw() interface{} { + switch v.Type() { + case ValueTypeEmpty: + return nil + case ValueTypeString: + return v.StringVal() + case ValueTypeBool: + return v.BoolVal() + case ValueTypeDouble: + return v.DoubleVal() + case ValueTypeInt: + return v.IntVal() + case ValueTypeBytes: + return v.BytesVal() + case ValueTypeMap: + v.MapVal().AsRaw() + case ValueTypeArray: + v.SliceVal().asRaw() + } + return fmt.Sprintf("", v.Type()) +} + func newAttributeKeyValueString(k string, v string) otlpcommon.KeyValue { orig := otlpcommon.KeyValue{Key: k} akv := Value{&orig.Value} @@ -489,9 +570,26 @@ func NewMap() Map { return Map{&orig} } +// NewMapFromRaw creates a Map with values from the given map[string]interface{}. +func NewMapFromRaw(rawMap map[string]interface{}) Map { + if len(rawMap) == 0 { + kv := []otlpcommon.KeyValue(nil) + return Map{&kv} + } + origs := make([]otlpcommon.KeyValue, len(rawMap)) + ix := 0 + for k, iv := range rawMap { + origs[ix].Key = k + newValueFromRaw(iv).copyTo(&origs[ix].Value) + ix++ + } + return Map{&origs} +} + // NewMapFromRaw creates a Map with values // from the given map[string]Value. -func NewMapFromRaw(rawMap map[string]Value) Map { +// Deprecated: [v0.48.0] Use NewMapFromRaw instead. +func NewAttributeMapFromMap(rawMap map[string]Value) Map { if len(rawMap) == 0 { kv := []otlpcommon.KeyValue(nil) return Map{&kv} @@ -837,6 +935,7 @@ func (m Map) CopyTo(dest Map) { func (m Map) AsRaw() map[string]interface{} { rawMap := make(map[string]interface{}) m.Range(func(k string, v Value) bool { + // TODO: Use v.asRaw() instead switch v.Type() { case ValueTypeString: rawMap[k] = v.StringVal() @@ -860,11 +959,25 @@ func (m Map) AsRaw() map[string]interface{} { return rawMap } +// newSliceFromRaw creates a Slice with values from the given []interface{}. +func newSliceFromRaw(rawSlice []interface{}) Slice { + if len(rawSlice) == 0 { + v := []otlpcommon.AnyValue(nil) + return Slice{&v} + } + origs := make([]otlpcommon.AnyValue, len(rawSlice)) + for ix, iv := range rawSlice { + newValueFromRaw(iv).copyTo(&origs[ix]) + } + return Slice{&origs} +} + // asRaw creates a slice out of a Slice. func (es Slice) asRaw() []interface{} { rawSlice := make([]interface{}, 0, es.Len()) for i := 0; i < es.Len(); i++ { v := es.At(i) + // TODO: Use v.asRaw() instead switch v.Type() { case ValueTypeString: rawSlice = append(rawSlice, v.StringVal()) diff --git a/model/internal/pdata/common_test.go b/model/internal/pdata/common_test.go index 2a9a5eeb1690..43bc9f79c2eb 100644 --- a/model/internal/pdata/common_test.go +++ b/model/internal/pdata/common_test.go @@ -568,13 +568,13 @@ func TestMapIterationNil(t *testing.T) { } func TestMap_Range(t *testing.T) { - rawMap := map[string]Value{ - "k_string": NewValueString("123"), - "k_int": NewValueInt(123), - "k_double": NewValueDouble(1.23), - "k_bool": NewValueBool(true), - "k_empty": NewValueEmpty(), - "k_bytes": NewValueBytes([]byte{}), + rawMap := map[string]interface{}{ + "k_string": "123", + "k_int": int64(123), + "k_double": float64(1.23), + "k_bool": true, + "k_empty": nil, + "k_bytes": []byte{}, } am := NewMapFromRaw(rawMap) assert.Equal(t, 6, am.Len()) @@ -587,21 +587,45 @@ func TestMap_Range(t *testing.T) { assert.Equal(t, 1, calls) am.Range(func(k string, v Value) bool { - assert.True(t, v.Equal(rawMap[k])) + assert.Equal(t, rawMap[k], v.asRaw()) delete(rawMap, k) return true }) assert.EqualValues(t, 0, len(rawMap)) } -func TestMap_InitFromMap(t *testing.T) { - am := NewMapFromRaw(map[string]Value(nil)) +func TestMap_InitFromRaw(t *testing.T) { + am := NewMapFromRaw(map[string]interface{}(nil)) + assert.EqualValues(t, NewMap(), am) + + rawMap := map[string]interface{}{ + "k_string": "123", + "k_int": 123, + "k_double": 1.23, + "k_bool": true, + "k_null": nil, + "k_bytes": []byte{1, 2, 3}, + } + rawOrig := []otlpcommon.KeyValue{ + newAttributeKeyValueString("k_string", "123"), + newAttributeKeyValueInt("k_int", 123), + newAttributeKeyValueDouble("k_double", 1.23), + newAttributeKeyValueBool("k_bool", true), + newAttributeKeyValueNull("k_null"), + newAttributeKeyValueBytes("k_bytes", []byte{1, 2, 3}), + } + am = NewMapFromRaw(rawMap) + assert.EqualValues(t, Map{orig: &rawOrig}.Sort(), am.Sort()) +} + +func TestMap_InitFromMapDeprecated(t *testing.T) { + am := NewAttributeMapFromMap(map[string]Value(nil)) assert.EqualValues(t, NewMap(), am) rawMap := map[string]Value{ "k_string": NewValueString("123"), - "k_int": NewValueInt(123), - "k_double": NewValueDouble(1.23), + "k_int": NewValueInt(int64(123)), + "k_double": NewValueDouble(float64(1.23)), "k_bool": NewValueBool(true), "k_null": NewValueEmpty(), "k_bytes": NewValueBytes([]byte{1, 2, 3}), @@ -614,7 +638,7 @@ func TestMap_InitFromMap(t *testing.T) { newAttributeKeyValueNull("k_null"), newAttributeKeyValueBytes("k_bytes", []byte{1, 2, 3}), } - am = NewMapFromRaw(rawMap) + am = NewAttributeMapFromMap(rawMap) assert.EqualValues(t, Map{orig: &rawOrig}.Sort(), am.Sort()) } @@ -733,13 +757,13 @@ func TestMap_Clear(t *testing.T) { } func TestMap_RemoveIf(t *testing.T) { - rawMap := map[string]Value{ - "k_string": NewValueString("123"), - "k_int": NewValueInt(123), - "k_double": NewValueDouble(1.23), - "k_bool": NewValueBool(true), - "k_empty": NewValueEmpty(), - "k_bytes": NewValueBytes([]byte{}), + rawMap := map[string]interface{}{ + "k_string": "123", + "k_int": int64(123), + "k_double": float64(1.23), + "k_bool": true, + "k_empty": nil, + "k_bytes": []byte{}, } am := NewMapFromRaw(rawMap) assert.Equal(t, 6, am.Len()) @@ -918,37 +942,37 @@ func generateTestMap() Map { } func fillTestMap(dest Map) { - NewMapFromRaw(map[string]Value{ - "k": NewValueString("v"), + NewMapFromRaw(map[string]interface{}{ + "k": "v", }).CopyTo(dest) } func generateTestEmptyMap() Map { - return NewMapFromRaw(map[string]Value{ - "k": NewValueEmpty(), + return NewMapFromRaw(map[string]interface{}{ + "k": nil, }) } func generateTestIntMap() Map { - return NewMapFromRaw(map[string]Value{ - "k": NewValueInt(123), + return NewMapFromRaw(map[string]interface{}{ + "k": 123, }) } func generateTestDoubleMap() Map { - return NewMapFromRaw(map[string]Value{ - "k": NewValueDouble(12.3), + return NewMapFromRaw(map[string]interface{}{ + "k": 12.3, }) } func generateTestBoolMap() Map { - return NewMapFromRaw(map[string]Value{ - "k": NewValueBool(true), + return NewMapFromRaw(map[string]interface{}{ + "k": true, }) } func generateTestBytesMap() Map { - return NewMapFromRaw(map[string]Value{ - "k": NewValueBytes([]byte{1, 2, 3, 4, 5}), + return NewMapFromRaw(map[string]interface{}{ + "k": []byte{1, 2, 3, 4, 5}, }) } @@ -1088,13 +1112,6 @@ func TestAsString(t *testing.T) { } func TestAsRaw(t *testing.T) { - arr := NewValueArray() - arr.SliceVal().AppendEmpty().SetBoolVal(false) - arr.SliceVal().AppendEmpty().SetBytesVal([]byte("test")) - arr.SliceVal().AppendEmpty().SetDoubleVal(12.9) - arr.SliceVal().AppendEmpty().SetIntVal(91) - arr.SliceVal().AppendEmpty().SetStringVal("another string") - tests := []struct { name string input Map @@ -1103,15 +1120,15 @@ func TestAsRaw(t *testing.T) { { name: "asraw", input: NewMapFromRaw( - map[string]Value{ - "array": arr, - "bool": NewValueBool(true), - "bytes": NewValueBytes([]byte("bytes value")), - "double": NewValueDouble(1.2), - "empty": NewValueEmpty(), - "int": NewValueInt(900), - "map": NewValueMap(), - "string": NewValueString("string value"), + map[string]interface{}{ + "array": []interface{}{false, []byte("test"), 12.9, int64(91), "another string"}, + "bool": true, + "bytes": []byte("bytes value"), + "double": 1.2, + "empty": nil, + "int": int64(900), + "map": map[string]interface{}{}, + "string": "string value", }, ), expected: map[string]interface{}{ @@ -1119,7 +1136,7 @@ func TestAsRaw(t *testing.T) { "bool": true, "bytes": []byte("bytes value"), "double": 1.2, - "empty": interface{}(nil), + "empty": nil, "int": int64(900), "map": map[string]interface{}{}, "string": "string value", @@ -1134,6 +1151,141 @@ func TestAsRaw(t *testing.T) { } } +func TestNewValueFromRaw(t *testing.T) { + tests := []struct { + name string + input interface{} + expected Value + }{ + { + name: "nil", + input: nil, + expected: NewValueEmpty(), + }, + { + name: "string", + input: "text", + expected: NewValueString("text"), + }, + { + name: "int", + input: 123, + expected: NewValueInt(int64(123)), + }, + { + name: "int8", + input: int8(12), + expected: NewValueInt(int64(12)), + }, + { + name: "int16", + input: int16(23), + expected: NewValueInt(int64(23)), + }, + { + name: "int32", + input: int32(34), + expected: NewValueInt(int64(34)), + }, + { + name: "int64", + input: int64(45), + expected: NewValueInt(45), + }, + { + name: "uint", + input: uint(56), + expected: NewValueInt(int64(56)), + }, + { + name: "uint8", + input: uint8(67), + expected: NewValueInt(int64(67)), + }, + { + name: "uint16", + input: uint16(78), + expected: NewValueInt(int64(78)), + }, + { + name: "uint32", + input: uint32(89), + expected: NewValueInt(int64(89)), + }, + { + name: "uint64", + input: uint64(90), + expected: NewValueInt(int64(90)), + }, + { + name: "float32", + input: float32(1.234), + expected: NewValueDouble(float64(float32(1.234))), + }, + { + name: "float64", + input: float64(2.345), + expected: NewValueDouble(float64(2.345)), + }, + { + name: "bool", + input: true, + expected: NewValueBool(true), + }, + { + name: "bytes", + input: []byte{1, 2, 3}, + expected: NewValueBytes([]byte{1, 2, 3}), + }, + { + name: "map", + input: generateTestMap(), + expected: func() Value { + m := NewValueMap() + generateTestMap().CopyTo(m.MapVal()) + return m + }(), + }, + { + name: "rawMap", + input: map[string]interface{}{ + "k": "v", + }, + expected: func() Value { + m := NewValueMap() + NewMapFromRaw(map[string]interface{}{ + "k": "v", + }).CopyTo(m.MapVal()) + return m + }(), + }, + { + name: "slice", + input: generateTestSlice(), + expected: (func() Value { + s := NewValueArray() + generateTestSlice().CopyTo(s.SliceVal()) + return s + })(), + }, + { + name: "rawSlice", + input: []interface{}{"v1", "v2"}, + expected: (func() Value { + s := NewValueArray() + newSliceFromRaw([]interface{}{"v1", "v2"}).CopyTo(s.SliceVal()) + return s + })(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := newValueFromRaw(tt.input) + assert.Equal(t, tt.expected, actual) + }) + } +} + func simpleValueMap() Value { ret := NewValueMap() attrMap := ret.MapVal() diff --git a/model/internal/pdata/metrics_test.go b/model/internal/pdata/metrics_test.go index 0e3319b666ea..56cab29c5d45 100644 --- a/model/internal/pdata/metrics_test.go +++ b/model/internal/pdata/metrics_test.go @@ -218,8 +218,8 @@ func TestOtlpToInternalReadOnly(t *testing.T) { assert.EqualValues(t, 1, resourceMetrics.Len()) resourceMetric := resourceMetrics.At(0) - assert.EqualValues(t, NewMapFromRaw(map[string]Value{ - "string": NewValueString("string-resource"), + assert.EqualValues(t, NewMapFromRaw(map[string]interface{}{ + "string": "string-resource", }), resourceMetric.Resource().Attributes()) metrics := resourceMetric.InstrumentationLibraryMetrics().At(0).Metrics() assert.EqualValues(t, 3, metrics.Len()) @@ -236,12 +236,12 @@ func TestOtlpToInternalReadOnly(t *testing.T) { assert.EqualValues(t, startTime, gaugeDataPoints.At(0).StartTimestamp()) assert.EqualValues(t, endTime, gaugeDataPoints.At(0).Timestamp()) assert.EqualValues(t, 123.1, gaugeDataPoints.At(0).DoubleVal()) - assert.EqualValues(t, NewMapFromRaw(map[string]Value{"key0": NewValueString("value0")}), gaugeDataPoints.At(0).Attributes()) + assert.EqualValues(t, NewMapFromRaw(map[string]interface{}{"key0": "value0"}), gaugeDataPoints.At(0).Attributes()) // Second point assert.EqualValues(t, startTime, gaugeDataPoints.At(1).StartTimestamp()) assert.EqualValues(t, endTime, gaugeDataPoints.At(1).Timestamp()) assert.EqualValues(t, 456.1, gaugeDataPoints.At(1).DoubleVal()) - assert.EqualValues(t, NewMapFromRaw(map[string]Value{"key1": NewValueString("value1")}), gaugeDataPoints.At(1).Attributes()) + assert.EqualValues(t, NewMapFromRaw(map[string]interface{}{"key1": "value1"}), gaugeDataPoints.At(1).Attributes()) // Check double metric metricDouble := metrics.At(1) @@ -257,12 +257,12 @@ func TestOtlpToInternalReadOnly(t *testing.T) { assert.EqualValues(t, startTime, sumDataPoints.At(0).StartTimestamp()) assert.EqualValues(t, endTime, sumDataPoints.At(0).Timestamp()) assert.EqualValues(t, 123.1, sumDataPoints.At(0).DoubleVal()) - assert.EqualValues(t, NewMapFromRaw(map[string]Value{"key0": NewValueString("value0")}), sumDataPoints.At(0).Attributes()) + assert.EqualValues(t, NewMapFromRaw(map[string]interface{}{"key0": "value0"}), sumDataPoints.At(0).Attributes()) // Second point assert.EqualValues(t, startTime, sumDataPoints.At(1).StartTimestamp()) assert.EqualValues(t, endTime, sumDataPoints.At(1).Timestamp()) assert.EqualValues(t, 456.1, sumDataPoints.At(1).DoubleVal()) - assert.EqualValues(t, NewMapFromRaw(map[string]Value{"key1": NewValueString("value1")}), sumDataPoints.At(1).Attributes()) + assert.EqualValues(t, NewMapFromRaw(map[string]interface{}{"key1": "value1"}), sumDataPoints.At(1).Attributes()) // Check histogram metric metricHistogram := metrics.At(2) @@ -278,13 +278,13 @@ func TestOtlpToInternalReadOnly(t *testing.T) { assert.EqualValues(t, startTime, histogramDataPoints.At(0).StartTimestamp()) assert.EqualValues(t, endTime, histogramDataPoints.At(0).Timestamp()) assert.EqualValues(t, []float64{1, 2}, histogramDataPoints.At(0).ExplicitBounds()) - assert.EqualValues(t, NewMapFromRaw(map[string]Value{"key0": NewValueString("value0")}), histogramDataPoints.At(0).Attributes()) + assert.EqualValues(t, NewMapFromRaw(map[string]interface{}{"key0": "value0"}), histogramDataPoints.At(0).Attributes()) assert.EqualValues(t, []uint64{10, 15, 1}, histogramDataPoints.At(0).BucketCounts()) // Second point assert.EqualValues(t, startTime, histogramDataPoints.At(1).StartTimestamp()) assert.EqualValues(t, endTime, histogramDataPoints.At(1).Timestamp()) assert.EqualValues(t, []float64{1}, histogramDataPoints.At(1).ExplicitBounds()) - assert.EqualValues(t, NewMapFromRaw(map[string]Value{"key1": NewValueString("value1")}), histogramDataPoints.At(1).Attributes()) + assert.EqualValues(t, NewMapFromRaw(map[string]interface{}{"key1": "value1"}), histogramDataPoints.At(1).Attributes()) assert.EqualValues(t, []uint64{10, 1}, histogramDataPoints.At(1).BucketCounts()) } @@ -319,7 +319,7 @@ func TestOtlpToFromInternalReadOnly(t *testing.T) { } func TestOtlpToFromInternalGaugeMutating(t *testing.T) { - newAttributes := NewMapFromRaw(map[string]Value{"k": NewValueString("v")}) + newAttributes := NewMapFromRaw(map[string]interface{}{"k": "v"}) md := MetricsFromOtlp(&otlpmetrics.MetricsData{ ResourceMetrics: []*otlpmetrics.ResourceMetrics{ @@ -402,7 +402,7 @@ func TestOtlpToFromInternalGaugeMutating(t *testing.T) { } func TestOtlpToFromInternalSumMutating(t *testing.T) { - newAttributes := NewMapFromRaw(map[string]Value{"k": NewValueString("v")}) + newAttributes := NewMapFromRaw(map[string]interface{}{"k": "v"}) md := MetricsFromOtlp(&otlpmetrics.MetricsData{ ResourceMetrics: []*otlpmetrics.ResourceMetrics{ @@ -487,7 +487,7 @@ func TestOtlpToFromInternalSumMutating(t *testing.T) { } func TestOtlpToFromInternalHistogramMutating(t *testing.T) { - newAttributes := NewMapFromRaw(map[string]Value{"k": NewValueString("v")}) + newAttributes := NewMapFromRaw(map[string]interface{}{"k": "v"}) md := MetricsFromOtlp(&otlpmetrics.MetricsData{ ResourceMetrics: []*otlpmetrics.ResourceMetrics{ @@ -571,7 +571,7 @@ func TestOtlpToFromInternalHistogramMutating(t *testing.T) { } func TestOtlpToFromInternalExponentialHistogramMutating(t *testing.T) { - newAttributes := NewMapFromRaw(map[string]Value{"k": NewValueString("v")}) + newAttributes := NewMapFromRaw(map[string]interface{}{"k": "v"}) md := MetricsFromOtlp(&otlpmetrics.MetricsData{ ResourceMetrics: []*otlpmetrics.ResourceMetrics{ diff --git a/model/pdata/common_alias.go b/model/pdata/common_alias.go index 7795799f7e61..cee3fe76eafe 100644 --- a/model/pdata/common_alias.go +++ b/model/pdata/common_alias.go @@ -119,7 +119,7 @@ var ( var NewAttributeMap = pdata.NewMap // Deprecated: [v0.48.0] Use NewMapFromRaw instead. -var NewAttributeMapFromMap = pdata.NewMapFromRaw +var NewAttributeMapFromMap = pdata.NewAttributeMapFromMap // Deprecated: [v0.48.0] Use Slice instead. type AttributeValueSlice = pdata.Slice