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

Added support for list values for a key in processor #1936

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions internal/processor/filterhelper/filterhelper.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,27 @@ func NewAttributeValueRaw(value interface{}) (pdata.AttributeValue, error) {
return pdata.NewAttributeValueString(val), nil
case bool:
return pdata.NewAttributeValueBool(val), nil
case []interface{}:
attributeVal, err := fromArray(val)
if err != nil {
return attributeVal, err
}
return attributeVal, nil
default:
return pdata.AttributeValue{}, fmt.Errorf("error unsupported value type \"%T\"", value)
}
}

func fromArray(val []interface{}) (pdata.AttributeValue, error) {
arr := pdata.NewAnyValueArray()
for _, v := range val {
attributeVal, err := NewAttributeValueRaw(v)
if err != nil {
return attributeVal, err
}
arr.Append(attributeVal)
}
av := pdata.NewAttributeValueArray()
av.SetArrayVal(arr)
return av, nil
}
59 changes: 59 additions & 0 deletions internal/processor/filterhelper/filterhelper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,62 @@ func TestHelper_AttributeValue(t *testing.T) {
_, err = NewAttributeValueRaw(t)
assert.Error(t, err)
}

func TestHelper_AttributeValueArray(t *testing.T) {
testData := []interface{}{"alpha", "beta", "gamma", "delta"}
val, err := NewAttributeValueRaw(testData)
assert.Equal(t, val.Type(), pdata.AttributeValueARRAY)
assert.NotNil(t, val.ArrayVal())
assert.Equal(t, 4, val.ArrayVal().Len())
assert.NoError(t, err)
for i := 0; i < val.ArrayVal().Len(); i++ {
assert.Equal(t, pdata.NewAttributeValueString(testData[i].(string)), val.ArrayVal().At(i))
}

testData = []interface{}{int64(200), int64(203), int64(500)}
val, err = NewAttributeValueRaw(testData)
assert.Equal(t, val.Type(), pdata.AttributeValueARRAY)
assert.NotNil(t, val.ArrayVal())
assert.Equal(t, 3, val.ArrayVal().Len())
assert.NoError(t, err)
for i := 0; i < val.ArrayVal().Len(); i++ {
assert.Equal(t, pdata.NewAttributeValueInt(testData[i].(int64)), val.ArrayVal().At(i))
}

testData = []interface{}{float32(5341.129312), float32(888.102)}
val, err = NewAttributeValueRaw(testData)
assert.Equal(t, val.Type(), pdata.AttributeValueARRAY)
assert.NotNil(t, val.ArrayVal())
assert.Equal(t, 2, val.ArrayVal().Len())
assert.NoError(t, err)
for i := 0; i < val.ArrayVal().Len(); i++ {
assert.Equal(t, pdata.NewAttributeValueDouble(float64(testData[i].(float32))), val.ArrayVal().At(i))
}

testData = []interface{}{true}
val, err = NewAttributeValueRaw(testData)
assert.Equal(t, val.Type(), pdata.AttributeValueARRAY)
assert.NotNil(t, val.ArrayVal())
assert.Equal(t, 1, val.ArrayVal().Len())
assert.NoError(t, err)
for i := 0; i < val.ArrayVal().Len(); i++ {
assert.Equal(t, pdata.NewAttributeValueBool(testData[i].(bool)), val.ArrayVal().At(i))
}

var southWeather = make(map[string]interface{})
southWeather["NY"] = 15.9
southWeather["VT"] = 13.1
southWeather["NH"] = 18.0
val, err = NewAttributeValueRaw(southWeather)
assert.Equal(t, pdata.AttributeValue{}, val)
assert.Error(t, err)

var northWeather = make(map[string]interface{})
northWeather["AR"] = 45.7
northWeather["TX"] = 43.3
northWeather["MS"] = 41.1

val, err = NewAttributeValueRaw([]interface{}{southWeather, northWeather})
assert.Equal(t, pdata.AttributeValue{}, val)
assert.Error(t, err)
}
16 changes: 15 additions & 1 deletion internal/processor/filtermatcher/attributematcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,22 @@ func (ma attributesMatcher) Match(attrs pdata.AttributeMap) bool {
return false
}
} else if property.AttributeValue != nil {
if !attr.Equal(*property.AttributeValue) {
propertyAttrValue := property.AttributeValue
switch propertyAttrValue.Type() {
// Case when Attribute Values are of list values.
case pdata.AttributeValueARRAY:
for i := 0; i < propertyAttrValue.ArrayVal().Len(); i++ {
// Check attr value is exists in the AttributeValue array.
// Equal checks for any of int, string, bool and double.
if attr.Equal(propertyAttrValue.ArrayVal().At(i)) {
return true
}
}
return false
default:
Comment on lines +108 to +120
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing this here I suggest that we move this code to attr.Equal. It already has a TODO comment that expects this code to be there.

Copy link
Author

@isgoutham isgoutham Oct 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats right. I tried doing that earlier.
#1936 (comment)

if !attr.Equal(*property.AttributeValue) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handling at attr.Equal(*property.AttributeValue) would be ideal case. But attr, exist := attrs.Get(property.Key) returns String type for array values under property.Key. And further it always goes under string case execution

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you point to the code where the return value is string?

Copy link
Author

@isgoutham isgoutham Oct 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here Get func. Though the property.AttributeValue is of ARRAY type (since NewAttributeValueRaw() returns NewAttributeValueArray as per my logic), the return value of Get method is of string type.

Otherwise handling at Equal func would be ideal. In fact, there is a // TODO: handle MAP and ARRAY data types. I have tried adding these cases, but attr is of string type and Equal method is falling under string case.

I have tried using attr.SetArrayVal() but this is changing whole attributes as array.

Anything should i be considering for these scenarios?

return false
}
}
}
}
Expand Down
69 changes: 69 additions & 0 deletions internal/processor/filterspan/filterspan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,3 +562,72 @@ func TestServiceNameForResource(t *testing.T) {
resource.Attributes().InsertString(conventions.AttributeServiceName, "test-service")
require.Equal(t, serviceNameForResource(resource), "test-service")
}

// TestSpan_Matching_Array tests matcher.MatchSpan for attributes specification against a span
// Attributes include array values and default values covering switch case in Properties matcher attributes.Match
func TestSpan_Matching_Array(t *testing.T) {
// True case
cfg := &filterconfig.MatchProperties{
Config: *createConfig(filterset.Strict),
Services: []string{"svc"},
Attributes: []filterconfig.Attribute{
{
Key: "http.url",
Value: []interface{}{"https://play.golang.org/"},
},
},
}

span := pdata.NewSpan()
span.InitEmpty()
span.Attributes().InsertString("http.url", "https://play.golang.org/")
assert.NotNil(t, span)

matcher, err := NewMatcher(cfg)
spanRes := matcher.MatchSpan(span, resource("svc"), pdata.NewInstrumentationLibrary())
require.NoError(t, err)
assert.NotNil(t, matcher)
assert.True(t, spanRes)

// False case
cfg = &filterconfig.MatchProperties{
Config: *createConfig(filterset.Strict),
Services: []string{"svc"},
Attributes: []filterconfig.Attribute{
{
Key: "keyBool",
Value: []interface{}{false},
},
},
}

span.Attributes().InsertBool("keyBool", true)
assert.NotNil(t, span)

matcher, err = NewMatcher(cfg)
spanRes = matcher.MatchSpan(span, resource("svc"), pdata.NewInstrumentationLibrary())
require.NoError(t, err)
assert.NotNil(t, matcher)
assert.False(t, spanRes)

// Default case
cfg = &filterconfig.MatchProperties{
Config: *createConfig(filterset.Strict),
Services: []string{"svc"},
Attributes: []filterconfig.Attribute{
{
Key: "keyInt",
Value: 1243,
},
},
}

span.Attributes().InsertInt("keyInt", 1243)
assert.NotNil(t, span)

matcher, err = NewMatcher(cfg)
spanRes = matcher.MatchSpan(span, resource("svc"), pdata.NewInstrumentationLibrary())
require.NoError(t, err)
assert.NotNil(t, matcher)
assert.True(t, spanRes)
}