From 3cfe4f8c5d3e9eb4e8289ea592018b41439250c4 Mon Sep 17 00:00:00 2001 From: alrex Date: Wed, 4 Aug 2021 12:15:44 -0700 Subject: [PATCH] adding support for Bytes attribute type (#3756) * adding support for Bytes attribute type * adding warning comment * update comments * update comments --- model/pdata/common.go | 72 ++++++++++++++++++++++++++++++++++++++ model/pdata/common_test.go | 71 ++++++++++++++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 1 deletion(-) diff --git a/model/pdata/common.go b/model/pdata/common.go index cf8e042c5df..c34ecd41d31 100644 --- a/model/pdata/common.go +++ b/model/pdata/common.go @@ -18,6 +18,7 @@ package pdata // such as timestamps, attributes, etc. import ( + "bytes" "sort" otlpcommon "go.opentelemetry.io/collector/model/internal/data/protogen/common/v1" @@ -34,6 +35,7 @@ const ( AttributeValueTypeBool AttributeValueTypeMap AttributeValueTypeArray + AttributeValueTypeBytes ) // String returns the string representation of the AttributeValueType. @@ -53,6 +55,8 @@ func (avt AttributeValueType) String() string { return "MAP" case AttributeValueTypeArray: return "ARRAY" + case AttributeValueTypeBytes: + return "BYTES" } return "" } @@ -116,6 +120,13 @@ func NewAttributeValueArray() AttributeValue { return AttributeValue{orig: &otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_ArrayValue{ArrayValue: &otlpcommon.ArrayValue{}}}} } +// NewAttributeValueBytes creates a new AttributeValue with the given []byte value. +// The caller must ensure the []byte passed in is not modified after the call is made, sharing the data +// across multiple attributes is forbidden. +func NewAttributeValueBytes(v []byte) AttributeValue { + return AttributeValue{orig: &otlpcommon.AnyValue{Value: &otlpcommon.AnyValue_BytesValue{BytesValue: v}}} +} + // Type returns the type of the value for this AttributeValue. // Calling this function on zero-initialized AttributeValue will cause a panic. func (a AttributeValue) Type() AttributeValueType { @@ -135,6 +146,8 @@ func (a AttributeValue) Type() AttributeValueType { return AttributeValueTypeMap case *otlpcommon.AnyValue_ArrayValue: return AttributeValueTypeArray + case *otlpcommon.AnyValue_BytesValue: + return AttributeValueTypeBytes } return AttributeValueTypeNull } @@ -193,6 +206,14 @@ func (a AttributeValue) ArrayVal() AnyValueArray { return newAnyValueArray(&arr.Values) } +// BytesVal returns the []byte value associated with this AttributeValue. +// If the Type() is not AttributeValueTypeBytes then returns false. +// Calling this function on zero-initialized AttributeValue will cause a panic. +// Modifying the returned []byte in-place is forbidden. +func (a AttributeValue) BytesVal() []byte { + return a.orig.GetBytesValue() +} + // SetStringVal replaces the string value associated with this AttributeValue, // it also changes the type to be AttributeValueTypeString. // Calling this function on zero-initialized AttributeValue will cause a panic. @@ -221,6 +242,15 @@ func (a AttributeValue) SetBoolVal(v bool) { a.orig.Value = &otlpcommon.AnyValue_BoolValue{BoolValue: v} } +// SetBytesVal replaces the []byte value associated with this AttributeValue, +// it also changes the type to be AttributeValueTypeBytes. +// Calling this function on zero-initialized AttributeValue will cause a panic. +// The caller must ensure the []byte passed in is not modified after the call is made, sharing the data +// across multiple attributes is forbidden. +func (a AttributeValue) SetBytesVal(v []byte) { + a.orig.Value = &otlpcommon.AnyValue_BytesValue{BytesValue: v} +} + // copyTo copies the value to AnyValue. Will panic if dest is nil. func (a AttributeValue) copyTo(dest *otlpcommon.AnyValue) { switch v := a.orig.Value.(type) { @@ -323,6 +353,8 @@ func (a AttributeValue) Equal(av AttributeValue) bool { } } return true + case *otlpcommon.AnyValue_BytesValue: + return bytes.Equal(v.BytesValue, av.orig.GetBytesValue()) } return false @@ -367,6 +399,13 @@ func newAttributeKeyValue(k string, av AttributeValue) otlpcommon.KeyValue { return orig } +func newAttributeKeyValueBytes(k string, v []byte) otlpcommon.KeyValue { + orig := otlpcommon.KeyValue{Key: k} + akv := AttributeValue{&orig.Value} + akv.SetBytesVal(v) + return orig +} + // AttributeMap stores a map of attribute keys to values. type AttributeMap struct { orig *[]otlpcommon.KeyValue @@ -503,6 +542,16 @@ func (am AttributeMap) InsertBool(k string, v bool) { } } +// InsertBytes adds the []byte Value to the map when the key does not exist. +// No action is applied to the map where the key already exists. +// The caller must ensure the []byte passed in is not modified after the call is made, sharing the data +// across multiple attributes is forbidden. +func (am AttributeMap) InsertBytes(k string, v []byte) { + if _, existing := am.Get(k); !existing { + *am.orig = append(*am.orig, newAttributeKeyValueBytes(k, v)) + } +} + // Update updates an existing AttributeValue with a value. // No action is applied to the map where the key does not exist. // @@ -548,6 +597,16 @@ func (am AttributeMap) UpdateBool(k string, v bool) { } } +// UpdateBytes updates an existing []byte Value with a value. +// No action is applied to the map where the key does not exist. +// The caller must ensure the []byte passed in is not modified after the call is made, sharing the data +// across multiple attributes is forbidden. +func (am AttributeMap) UpdateBytes(k string, v []byte) { + if av, existing := am.Get(k); existing { + av.SetBytesVal(v) + } +} + // Upsert performs the Insert or Update action. The AttributeValue is // inserted to the map that did not originally have the key. The key/value is // updated to the map where the key already existed. @@ -608,6 +667,19 @@ func (am AttributeMap) UpsertBool(k string, v bool) { } } +// UpsertBytes performs the Insert or Update action. The []byte Value is +// inserted to the map that did not originally have the key. The key/value is +// updated to the map where the key already existed. +// The caller must ensure the []byte passed in is not modified after the call is made, sharing the data +// across multiple attributes is forbidden. +func (am AttributeMap) UpsertBytes(k string, v []byte) { + if av, existing := am.Get(k); existing { + av.SetBytesVal(v) + } else { + *am.orig = append(*am.orig, newAttributeKeyValueBytes(k, v)) + } +} + // Sort sorts the entries in the AttributeMap so two instances can be compared. // Returns the same instance to allow nicer code like: // assert.EqualValues(t, expected.Sort(), actual.Sort()) diff --git a/model/pdata/common_test.go b/model/pdata/common_test.go index fdc66f82542..33921b3e197 100644 --- a/model/pdata/common_test.go +++ b/model/pdata/common_test.go @@ -59,6 +59,11 @@ func TestAttributeValue(t *testing.T) { v.SetBoolVal(true) assert.EqualValues(t, AttributeValueTypeBool, v.Type()) assert.True(t, v.BoolVal()) + + bytesValue := []byte{1, 2, 3, 4} + v = NewAttributeValueBytes(bytesValue) + assert.EqualValues(t, AttributeValueTypeBytes, v.Type()) + assert.EqualValues(t, bytesValue, v.BytesVal()) } func TestAttributeValueType(t *testing.T) { @@ -69,6 +74,7 @@ func TestAttributeValueType(t *testing.T) { assert.EqualValues(t, "DOUBLE", AttributeValueTypeDouble.String()) assert.EqualValues(t, "MAP", AttributeValueTypeMap.String()) assert.EqualValues(t, "ARRAY", AttributeValueTypeArray.String()) + assert.EqualValues(t, "BYTES", AttributeValueTypeBytes.String()) } func TestAttributeValueMap(t *testing.T) { @@ -164,6 +170,10 @@ func TestNilOrigSetAttributeValue(t *testing.T) { av = NewAttributeValueNull() av.SetDoubleVal(1.23) assert.EqualValues(t, 1.23, av.DoubleVal()) + + av = NewAttributeValueNull() + av.SetBytesVal([]byte{1, 2, 3}) + assert.Equal(t, []byte{1, 2, 3}, av.BytesVal()) } func TestAttributeValueEqual(t *testing.T) { @@ -211,6 +221,16 @@ func TestAttributeValueEqual(t *testing.T) { av1 = NewAttributeValueBool(false) assert.True(t, av1.Equal(av2)) + av2 = NewAttributeValueBytes([]byte{1, 2, 3}) + assert.False(t, av1.Equal(av2)) + assert.False(t, av2.Equal(av1)) + + av1 = NewAttributeValueBytes([]byte{1, 2, 4}) + assert.False(t, av1.Equal(av2)) + + av1 = NewAttributeValueBytes([]byte{1, 2, 3}) + assert.True(t, av1.Equal(av2)) + av1 = NewAttributeValueArray() av1.ArrayVal().AppendEmpty().SetIntVal(123) assert.False(t, av1.Equal(av2)) @@ -279,6 +299,10 @@ func TestNilAttributeMap(t *testing.T) { insertMapBool.InsertBool("k", true) assert.EqualValues(t, generateTestBoolAttributeMap(), insertMapBool) + insertMapBytes := NewAttributeMap() + insertMapBytes.InsertBytes("k", []byte{1, 2, 3, 4, 5}) + assert.EqualValues(t, generateTestBytesAttributeMap(), insertMapBytes) + updateMap := NewAttributeMap() updateMap.Update("k", NewAttributeValueString("v")) assert.EqualValues(t, NewAttributeMap(), updateMap) @@ -299,6 +323,10 @@ func TestNilAttributeMap(t *testing.T) { updateMapBool.UpdateBool("k", true) assert.EqualValues(t, NewAttributeMap(), updateMapBool) + updateMapBytes := NewAttributeMap() + updateMapBytes.UpdateBytes("k", []byte{1, 2, 3}) + assert.EqualValues(t, NewAttributeMap(), updateMapBytes) + upsertMap := NewAttributeMap() upsertMap.Upsert("k", NewAttributeValueString("v")) assert.EqualValues(t, generateTestAttributeMap(), upsertMap) @@ -319,6 +347,10 @@ func TestNilAttributeMap(t *testing.T) { upsertMapBool.UpsertBool("k", true) assert.EqualValues(t, generateTestBoolAttributeMap(), upsertMapBool) + upsertMapBytes := NewAttributeMap() + upsertMapBytes.UpsertBytes("k", []byte{1, 2, 3, 4, 5}) + assert.EqualValues(t, generateTestBytesAttributeMap(), upsertMapBytes) + deleteMap := NewAttributeMap() assert.False(t, deleteMap.Delete("k")) assert.EqualValues(t, NewAttributeMap(), deleteMap) @@ -382,6 +414,12 @@ func TestAttributeMapWithEmpty(t *testing.T) { assert.EqualValues(t, AttributeValueTypeBool, val.Type()) assert.True(t, val.BoolVal()) + sm.InsertBytes("other_key_bytes", []byte{1, 2, 3}) + val, exist = sm.Get("other_key_bytes") + assert.True(t, exist) + assert.EqualValues(t, AttributeValueTypeBytes, val.Type()) + assert.EqualValues(t, []byte{1, 2, 3}, val.BytesVal()) + sm.Update("other_key", NewAttributeValueString("yet_another_value")) val, exist = sm.Get("other_key") assert.True(t, exist) @@ -412,6 +450,12 @@ func TestAttributeMapWithEmpty(t *testing.T) { assert.EqualValues(t, AttributeValueTypeBool, val.Type()) assert.False(t, val.BoolVal()) + sm.UpdateBytes("other_key_bytes", []byte{4, 5, 6}) + val, exist = sm.Get("other_key_bytes") + assert.True(t, exist) + assert.EqualValues(t, AttributeValueTypeBytes, val.Type()) + assert.EqualValues(t, []byte{4, 5, 6}, val.BytesVal()) + sm.Upsert("other_key", NewAttributeValueString("other_value")) val, exist = sm.Get("other_key") assert.True(t, exist) @@ -442,6 +486,12 @@ func TestAttributeMapWithEmpty(t *testing.T) { assert.EqualValues(t, AttributeValueTypeBool, val.Type()) assert.True(t, val.BoolVal()) + sm.UpsertBytes("other_key_bytes", []byte{7, 8, 9}) + val, exist = sm.Get("other_key_bytes") + assert.True(t, exist) + assert.EqualValues(t, AttributeValueTypeBytes, val.Type()) + assert.EqualValues(t, []byte{7, 8, 9}, val.BytesVal()) + sm.Upsert("yet_another_key", NewAttributeValueString("yet_another_value")) val, exist = sm.Get("yet_another_key") assert.True(t, exist) @@ -472,16 +522,24 @@ func TestAttributeMapWithEmpty(t *testing.T) { assert.EqualValues(t, AttributeValueTypeBool, val.Type()) assert.False(t, val.BoolVal()) + sm.UpsertBytes("yet_another_key_bytes", []byte{1}) + val, exist = sm.Get("yet_another_key_bytes") + assert.True(t, exist) + assert.EqualValues(t, AttributeValueTypeBytes, val.Type()) + assert.EqualValues(t, []byte{1}, val.BytesVal()) + assert.True(t, sm.Delete("other_key")) assert.True(t, sm.Delete("other_key_string")) assert.True(t, sm.Delete("other_key_int")) assert.True(t, sm.Delete("other_key_double")) assert.True(t, sm.Delete("other_key_bool")) + assert.True(t, sm.Delete("other_key_bytes")) assert.True(t, sm.Delete("yet_another_key")) assert.True(t, sm.Delete("yet_another_key_string")) assert.True(t, sm.Delete("yet_another_key_int")) assert.True(t, sm.Delete("yet_another_key_double")) assert.True(t, sm.Delete("yet_another_key_bool")) + assert.True(t, sm.Delete("yet_another_key_bytes")) assert.False(t, sm.Delete("other_key")) assert.False(t, sm.Delete("yet_another_key")) @@ -518,9 +576,10 @@ func TestAttributeMap_Range(t *testing.T) { "k_double": NewAttributeValueDouble(1.23), "k_bool": NewAttributeValueBool(true), "k_null": NewAttributeValueNull(), + "k_bytes": NewAttributeValueBytes([]byte{}), } am := NewAttributeMap().InitFromMap(rawMap) - assert.Equal(t, 5, am.Len()) + assert.Equal(t, 6, am.Len()) calls := 0 am.Range(func(k string, v AttributeValue) bool { @@ -547,6 +606,7 @@ func TestAttributeMap_InitFromMap(t *testing.T) { "k_double": NewAttributeValueDouble(1.23), "k_bool": NewAttributeValueBool(true), "k_null": NewAttributeValueNull(), + "k_bytes": NewAttributeValueBytes([]byte{1, 2, 3}), } rawOrig := []otlpcommon.KeyValue{ newAttributeKeyValueString("k_string", "123"), @@ -554,6 +614,7 @@ func TestAttributeMap_InitFromMap(t *testing.T) { newAttributeKeyValueDouble("k_double", 1.23), newAttributeKeyValueBool("k_bool", true), newAttributeKeyValueNull("k_null"), + newAttributeKeyValueBytes("k_bytes", []byte{1, 2, 3}), } am = NewAttributeMap().InitFromMap(rawMap) assert.EqualValues(t, AttributeMap{orig: &rawOrig}.Sort(), am.Sort()) @@ -1091,6 +1152,14 @@ func generateTestBoolAttributeMap() AttributeMap { return am } +func generateTestBytesAttributeMap() AttributeMap { + am := NewAttributeMap() + am.InitFromMap(map[string]AttributeValue{ + "k": NewAttributeValueBytes([]byte{1, 2, 3, 4, 5}), + }) + return am +} + func TestAttributeValueArray(t *testing.T) { a1 := NewAttributeValueArray() assert.EqualValues(t, AttributeValueTypeArray, a1.Type())