Skip to content

Commit

Permalink
[exporter/awsxray] Add support for AWS X-Ray annotations attribute in…
Browse files Browse the repository at this point in the history
… exporter. (#17855)

Add support for AWS X-Ray annotations attribute in AWS X-Ray exporter.

Add to generated spans in AWS X-Ray receiver.
  • Loading branch information
jefchien committed Jan 26, 2023
1 parent 395c731 commit 8049c8c
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 21 deletions.
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:
}
}
}
}
15 changes: 14 additions & 1 deletion receiver/awsxrayreceiver/internal/translator/annotations_test.go
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

0 comments on commit 8049c8c

Please sign in to comment.