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

[exporter/awsxray] Add support for AWS X-Ray annotations attribute in exporter. #17855

Merged
merged 1 commit into from
Jan 26, 2023
Merged
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
16 changes: 16 additions & 0 deletions .chloggen/forward-xray-annotations.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: exporter/awsxray

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Adds `aws.xray.annotations` attribute to forward annotation keys from the AWS X-Ray receiver to the AWS X-Ray exporter.

# One or more tracking issues related to the change
issues: [17550]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
2 changes: 1 addition & 1 deletion exporter/awsxrayexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ by the Span Resource object. X-Ray uses this data to generate inferred segments

## Exporter Configuration

The following exporter configuration parameters are supported. They mirror and have the same affect as the
The following exporter configuration parameters are supported. They mirror and have the same effect as the
comparable AWS X-Ray Daemon configuration values.

| Name | Description | Default |
Expand Down
14 changes: 14 additions & 0 deletions exporter/awsxrayexporter/internal/translator/segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,20 @@ func makeXRayAttributes(attributes map[string]pcommon.Value, resource pcommon.Re
}
}

annotationKeys, ok := attributes[awsxray.AWSXraySegmentAnnotationsAttribute]
if ok && annotationKeys.Type() == pcommon.ValueTypeSlice {
slice := annotationKeys.Slice()
for i := 0; i < slice.Len(); i++ {
value := slice.At(i)
if value.Type() != pcommon.ValueTypeStr {
continue
}
key := value.AsString()
indexedKeys[key] = true
}
delete(attributes, awsxray.AWSXraySegmentAnnotationsAttribute)
}

if storeResource {
resource.Attributes().Range(func(key string, value pcommon.Value) bool {
key = "otel.resource." + key
Expand Down
23 changes: 23 additions & 0 deletions exporter/awsxrayexporter/internal/translator/segment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,24 @@ func TestSpanWithAttributesPartlyIndexed(t *testing.T) {
assert.Equal(t, "val2", segment.Metadata["default"]["attr2@2"])
}

func TestSpanWithAnnotationsAttribute(t *testing.T) {
spanName := "/api/locations"
parentSpanID := newSegmentID()
attributes := make(map[string]interface{})
attributes["attr1@1"] = "val1"
attributes["attr2@2"] = "val2"
attributes[awsxray.AWSXraySegmentAnnotationsAttribute] = []string{"attr2@2", "not_exist"}
resource := constructDefaultResource()
span := constructServerSpan(parentSpanID, spanName, ptrace.StatusCodeError, "OK", attributes)

segment, _ := MakeSegment(span, resource, nil, false, nil)

assert.NotNil(t, segment)
assert.Equal(t, 1, len(segment.Annotations))
assert.Equal(t, "val2", segment.Annotations["attr2_2"])
assert.Equal(t, "val1", segment.Metadata["default"]["attr1@1"])
}

func TestSpanWithAttributesAllIndexed(t *testing.T) {
spanName := "/api/locations"
parentSpanID := newSegmentID()
Expand Down Expand Up @@ -864,6 +882,11 @@ func constructSpanAttributes(attributes map[string]interface{}) pcommon.Map {
attrs.PutInt(key, int64(cast))
} else if cast, ok := value.(int64); ok {
attrs.PutInt(key, cast)
} else if cast, ok := value.([]string); ok {
slice := attrs.PutEmptySlice(key)
for _, v := range cast {
slice.AppendEmpty().SetStr(v)
}
} else {
attrs.PutStr(key, fmt.Sprintf("%v", value))
}
Expand Down
4 changes: 4 additions & 0 deletions internal/aws/xray/awsxray.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ const (
// AWSXRayTracedAttribute is the `traced` field in an X-Ray subsegment
AWSXRayTracedAttribute = "aws.xray.traced"

// AWSXraySegmentAnnotationsAttribute is the attribute that
// will be treated by the X-Ray exporter as the annotation keys.
AWSXraySegmentAnnotationsAttribute = "aws.xray.annotations"

// AWSXraySegmentMetadataAttributePrefix is the prefix of the attribute that
// will be treated by the X-Ray exporter as metadata. The key of a metadata
// will be AWSXraySegmentMetadataAttributePrefix + <metadata_key>.
Expand Down
1 change: 1 addition & 0 deletions receiver/awsxrayreceiver/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.18

require (
github.com/aws/aws-sdk-go v1.44.186
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.0
github.com/open-telemetry/opentelemetry-collector-contrib/internal/aws/proxy v0.70.0
github.com/open-telemetry/opentelemetry-collector-contrib/internal/aws/xray v0.70.0
Expand Down
1 change: 1 addition & 0 deletions receiver/awsxrayreceiver/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 27 additions & 18 deletions receiver/awsxrayreceiver/internal/translator/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,35 @@

package translator // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/awsxrayreceiver/internal/translator"

import "go.opentelemetry.io/collector/pdata/pcommon"
import (
"go.opentelemetry.io/collector/pdata/pcommon"

awsxray "github.com/open-telemetry/opentelemetry-collector-contrib/internal/aws/xray"
)

func addAnnotations(annos map[string]interface{}, attrs pcommon.Map) {
for k, v := range annos {
switch t := v.(type) {
case int:
attrs.PutInt(k, int64(t))
case int32:
attrs.PutInt(k, int64(t))
case int64:
attrs.PutInt(k, t)
case string:
attrs.PutStr(k, t)
case bool:
attrs.PutBool(k, t)
case float32:
attrs.PutDouble(k, float64(t))
case float64:
attrs.PutDouble(k, t)
default:
if len(annos) > 0 {
keys := attrs.PutEmptySlice(awsxray.AWSXraySegmentAnnotationsAttribute)
keys.EnsureCapacity(len(annos))
for k, v := range annos {
keys.AppendEmpty().SetStr(k)
switch t := v.(type) {
case int:
attrs.PutInt(k, int64(t))
case int32:
attrs.PutInt(k, int64(t))
case int64:
attrs.PutInt(k, t)
case string:
attrs.PutStr(k, t)
case bool:
attrs.PutBool(k, t)
case float32:
attrs.PutDouble(k, float64(t))
case float64:
attrs.PutDouble(k, t)
default:
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ package translator
import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/assert"
"go.opentelemetry.io/collector/pdata/pcommon"

awsxray "github.com/open-telemetry/opentelemetry-collector-contrib/internal/aws/xray"
)

func TestAddAnnotations(t *testing.T) {
Expand All @@ -41,6 +45,15 @@ func TestAddAnnotations(t *testing.T) {
expectedAttrMap.PutInt("int", 0)
expectedAttrMap.PutInt("int32", 1)
expectedAttrMap.PutInt("int64", 2)
expectedKeys := expectedAttrMap.PutEmptySlice(awsxray.AWSXraySegmentAnnotationsAttribute)
expectedKeys.AppendEmpty().SetStr("int")
expectedKeys.AppendEmpty().SetStr("int32")
expectedKeys.AppendEmpty().SetStr("int64")
expectedKeys.AppendEmpty().SetStr("bool")
expectedKeys.AppendEmpty().SetStr("float32")
expectedKeys.AppendEmpty().SetStr("float64")

assert.Equal(t, expectedAttrMap.AsRaw(), attrMap.AsRaw(), "attribute maps differ")
assert.True(t, cmp.Equal(expectedAttrMap.AsRaw(), attrMap.AsRaw(), cmpopts.SortSlices(func(x, y interface{}) bool {
return x.(string) < y.(string)
})), "attribute maps differ")
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,15 +154,17 @@ func TestTranslation(t *testing.T) {
// this is the subsegment with ID that starts with 7df6
subseg7df6 := seg.Subsegments[0]
childSpan7df6Attrs := pcommon.NewMap()
childKeys := childSpan7df6Attrs.PutEmptySlice(awsxray.AWSXraySegmentAnnotationsAttribute)
for k, v := range subseg7df6.Annotations {
childSpan7df6Attrs.PutStr(k, v.(string))
childKeys.AppendEmpty().SetStr(k)
}
for k, v := range subseg7df6.Metadata {
m, err := json.Marshal(v)
assert.NoError(t, err, "metadata marshaling failed")
childSpan7df6Attrs.PutStr(awsxray.AWSXraySegmentMetadataAttributePrefix+k, string(m))
}
assert.Equal(t, 2, childSpan7df6Attrs.Len(), testCase+": childSpan7df6Attrs has incorrect size")
assert.Equal(t, 3, childSpan7df6Attrs.Len(), testCase+": childSpan7df6Attrs has incorrect size")
childSpan7df6Evts := initExceptionEvents(&subseg7df6)
assert.Len(t, childSpan7df6Evts, 1, testCase+": childSpan7df6Evts has incorrect size")
childSpan7df6 := perSpanProperties{
Expand Down