From 5a3dcf615e34f865f4982bd5febd1f718a6d3cd6 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Mon, 25 Aug 2025 17:13:14 -0700 Subject: [PATCH 1/6] set namespace to remote for producer spans --- .../internal/translator/segment.go | 3 +-- .../internal/translator/segment_test.go | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/exporter/awsxrayexporter/internal/translator/segment.go b/exporter/awsxrayexporter/internal/translator/segment.go index 98f6211cd1fde..421de3e2234a4 100644 --- a/exporter/awsxrayexporter/internal/translator/segment.go +++ b/exporter/awsxrayexporter/internal/translator/segment.go @@ -458,8 +458,7 @@ func MakeSegment(span ptrace.Span, resource pcommon.Resource, indexedAttrs []str if name == "" { name = fixSegmentName(span.Name()) } - - if namespace == "" && span.Kind() == ptrace.SpanKindClient { + if namespace == "" && (span.Kind() == ptrace.SpanKindClient || span.Kind() == ptrace.SpanKindProducer) { namespace = "remote" } diff --git a/exporter/awsxrayexporter/internal/translator/segment_test.go b/exporter/awsxrayexporter/internal/translator/segment_test.go index 6351ad99922cb..b3e16471d41b9 100644 --- a/exporter/awsxrayexporter/internal/translator/segment_test.go +++ b/exporter/awsxrayexporter/internal/translator/segment_test.go @@ -1166,6 +1166,7 @@ func TestProducerSpanWithAwsRemoteServiceName(t *testing.T) { segment, _ := MakeSegment(span, resource, nil, false, nil, false) assert.Equal(t, "ProducerService", *segment.Name) assert.Equal(t, "subsegment", *segment.Type) + assert.Equal(t, "remote", *segment.Namespace) jsonStr, err := MakeSegmentDocumentString(span, resource, nil, false, nil, false) @@ -1176,6 +1177,22 @@ func TestProducerSpanWithAwsRemoteServiceName(t *testing.T) { assert.NotContains(t, jsonStr, "user") } +func TestProducerSpanNonAwsRemoteServiceName(t *testing.T) { + spanName := "my-topic send" + parentSpanID := newSegmentID() + attributes := make(map[string]any) + attributes[conventions.AttributePeerService] = "ProducerService" + resource := constructDefaultResource() + span := constructProducerSpan(parentSpanID, spanName, ptrace.StatusCodeOk, "OK", attributes) + + segment, _ := MakeSegment(span, resource, nil, false, nil, false) + + assert.NotNil(t, segment) + assert.Equal(t, "ProducerService", *segment.Name) + assert.Equal(t, "subsegment", *segment.Type) + assert.Equal(t, "remote", *segment.Namespace) +} + func TestConsumerSpanWithAwsRemoteServiceName(t *testing.T) { spanName := "ABC.payment" parentSpanID := newSegmentID() From f3078e764732b28e7239acffab313873bf08251d Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 10 Sep 2025 16:39:49 -0700 Subject: [PATCH 2/6] set Consumer span to be segment --- exporter/awsxrayexporter/internal/translator/segment.go | 1 + 1 file changed, 1 insertion(+) diff --git a/exporter/awsxrayexporter/internal/translator/segment.go b/exporter/awsxrayexporter/internal/translator/segment.go index 421de3e2234a4..2ceea2b0f783d 100644 --- a/exporter/awsxrayexporter/internal/translator/segment.go +++ b/exporter/awsxrayexporter/internal/translator/segment.go @@ -329,6 +329,7 @@ func MakeSegment(span ptrace.Span, resource pcommon.Resource, indexedAttrs []str storeResource := true if span.Kind() != ptrace.SpanKindServer && + span.Kind() != ptrace.SpanKindConsumer && !span.ParentSpanID().IsEmpty() { segmentType = "subsegment" // We only store the resource information for segments, the local root. From 8f6434fa7e223ab074ef1892c23ba04fc958876f Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 10 Sep 2025 17:12:56 -0700 Subject: [PATCH 3/6] update test case for consumer spans --- .../internal/translator/segment_test.go | 78 +++++++++++++++++-- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/exporter/awsxrayexporter/internal/translator/segment_test.go b/exporter/awsxrayexporter/internal/translator/segment_test.go index b3e16471d41b9..6338f6c9f1b8d 100644 --- a/exporter/awsxrayexporter/internal/translator/segment_test.go +++ b/exporter/awsxrayexporter/internal/translator/segment_test.go @@ -1306,6 +1306,72 @@ func validateLocalRootServiceSegment(t *testing.T, segment *awsxray.Segment, spa assert.Nil(t, segment.Namespace) } +func validateLocalRootSegmentTypeDependencySubsegment(t *testing.T, segment *awsxray.Segment, span ptrace.Span, parentID string) { + tempTraceID := span.TraceID() + expectedTraceID := "1-" + fmt.Sprintf("%x", tempTraceID[0:4]) + "-" + fmt.Sprintf("%x", tempTraceID[4:16]) + + assert.Equal(t, "subsegment", *segment.Type) + assert.Equal(t, "myRemoteService", *segment.Name) + assert.Equal(t, span.SpanID().String(), *segment.ID) + assert.Equal(t, parentID, *segment.ParentID) + assert.Equal(t, expectedTraceID, *segment.TraceID) + assert.NotNil(t, segment.HTTP) + assert.Equal(t, "POST", *segment.HTTP.Request.Method) + assert.Len(t, segment.Annotations, 2) + assert.Nil(t, segment.Annotations[awsRemoteService]) + assert.Nil(t, segment.Annotations[remoteTarget]) + assert.Equal(t, "myAnnotationValue", segment.Annotations["myAnnotationKey"]) + + assert.Len(t, segment.Metadata["default"], 30) + assert.Equal(t, "receive", segment.Metadata["default"][conventions.AttributeMessagingOperation]) + assert.Equal(t, "LOCAL_ROOT", segment.Metadata["default"][awsSpanKind]) + assert.Equal(t, "myRemoteOperation", segment.Metadata["default"][awsRemoteOperation]) + assert.Equal(t, "myTarget", segment.Metadata["default"][remoteTarget]) + assert.Equal(t, "k8sRemoteNamespace", segment.Metadata["default"][k8sRemoteNamespace]) + assert.Equal(t, "myLocalService", segment.Metadata["default"][awsLocalService]) + assert.Equal(t, "awsLocalOperation", segment.Metadata["default"][awsLocalOperation]) + assert.Equal(t, "service.name=myTest", segment.Metadata["default"]["otel.resource.attributes"]) + + assert.Equal(t, "MySDK", *segment.AWS.XRay.SDK) + assert.Equal(t, "1.20.0", *segment.AWS.XRay.SDKVersion) + assert.True(t, *segment.AWS.XRay.AutoInstrumentation) + + assert.Equal(t, "UpdateItem", *segment.AWS.Operation) + assert.Equal(t, "AWSAccountAttribute", *segment.AWS.AccountID) + assert.Equal(t, "AWSRegionAttribute", *segment.AWS.RemoteRegion) + assert.Equal(t, "AWSRequestIDAttribute", *segment.AWS.RequestID) + assert.Equal(t, "AWSQueueURLAttribute", *segment.AWS.QueueURL) + assert.Equal(t, "TableName", *segment.AWS.TableName) + + assert.Equal(t, "remote", *segment.Namespace) +} + +func validateLocalRootSegmentTypeServiceSegment(t *testing.T, segment *awsxray.Segment, span ptrace.Span) { + tempTraceID := span.TraceID() + expectedTraceID := "1-" + fmt.Sprintf("%x", tempTraceID[0:4]) + "-" + fmt.Sprintf("%x", tempTraceID[4:16]) + + assert.Nil(t, segment.Type) + assert.Equal(t, "myLocalService", *segment.Name) + assert.Equal(t, expectedTraceID, *segment.TraceID) + assert.Nil(t, segment.HTTP) + assert.Len(t, segment.Annotations, 1) + assert.Equal(t, "myAnnotationValue", segment.Annotations["myAnnotationKey"]) + assert.Len(t, segment.Metadata["default"], 23) + assert.Equal(t, "service.name=myTest", segment.Metadata["default"]["otel.resource.attributes"]) + assert.Equal(t, "MySDK", *segment.AWS.XRay.SDK) + assert.Equal(t, "1.20.0", *segment.AWS.XRay.SDKVersion) + assert.True(t, *segment.AWS.XRay.AutoInstrumentation) + assert.Nil(t, segment.AWS.Operation) + assert.Nil(t, segment.AWS.AccountID) + assert.Nil(t, segment.AWS.RemoteRegion) + assert.Nil(t, segment.AWS.RequestID) + assert.Nil(t, segment.AWS.QueueURL) + assert.Nil(t, segment.AWS.TableName) + assert.Nil(t, segment.Namespace) + + assert.Nil(t, segment.Namespace) +} + func getBasicAttributes() map[string]any { attributes := make(map[string]any) @@ -1370,10 +1436,10 @@ func TestLocalRootConsumer(t *testing.T) { assert.Len(t, segments, 2) assert.NoError(t, err) - validateLocalRootDependencySubsegment(t, segments[0], span, *segments[1].ID) + validateLocalRootSegmentTypeDependencySubsegment(t, segments[0], span, *segments[1].ID) assert.Nil(t, segments[0].Links) - validateLocalRootServiceSegment(t, segments[1], span) + validateLocalRootSegmentTypeServiceSegment(t, segments[1], span) assert.Len(t, segments[1].Links, 1) // Checks these values are the same for both @@ -1405,7 +1471,7 @@ func TestNonLocalRootConsumerProcess(t *testing.T) { expectedTraceID := "1-" + fmt.Sprintf("%x", tempTraceID[0:4]) + "-" + fmt.Sprintf("%x", tempTraceID[4:16]) // Validate segment 1 (dependency subsegment) - assert.Equal(t, "subsegment", *segments[0].Type) + assert.Nil(t, segments[0].Type) assert.Equal(t, "destination operation", *segments[0].Name) assert.NotEqual(t, parentSpanID.String(), *segments[0].ID) assert.Equal(t, span.SpanID().String(), *segments[0].ID) @@ -1415,7 +1481,7 @@ func TestNonLocalRootConsumerProcess(t *testing.T) { assert.Equal(t, "POST", *segments[0].HTTP.Request.Method) assert.Len(t, segments[0].Annotations, 1) assert.Equal(t, "myAnnotationValue", segments[0].Annotations["myAnnotationKey"]) - assert.Len(t, segments[0].Metadata["default"], 7) + assert.Len(t, segments[0].Metadata["default"], 29) assert.Equal(t, "Consumer", segments[0].Metadata["default"][awsSpanKind]) assert.Equal(t, "myLocalService", segments[0].Metadata["default"][awsLocalService]) assert.Equal(t, "receive", segments[0].Metadata["default"][conventions.AttributeMessagingOperation]) @@ -1680,8 +1746,8 @@ func TestNotLocalRootConsumer(t *testing.T) { assert.NoError(t, err) // Validate segment - assert.Equal(t, "subsegment", *segments[0].Type) - assert.Equal(t, "remote", *segments[0].Namespace) + assert.Nil(t, segments[0].Type) + assert.Nil(t, segments[0].Namespace) assert.Equal(t, "myRemoteService", *segments[0].Name) } From 43d9ec36f4da21f5f9d6c680f106af20fe14bb0a Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 11 Sep 2025 08:48:18 -0700 Subject: [PATCH 4/6] add changelog entry --- ...awsxrayexporter-fix-messaging-tracing.yaml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .chloggen/awsxrayexporter-fix-messaging-tracing.yaml diff --git a/.chloggen/awsxrayexporter-fix-messaging-tracing.yaml b/.chloggen/awsxrayexporter-fix-messaging-tracing.yaml new file mode 100644 index 0000000000000..6c66518847e93 --- /dev/null +++ b/.chloggen/awsxrayexporter-fix-messaging-tracing.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: awsxrayexporter + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: infer downstream service for producer spans + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [40995] + +# (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: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] From d5ad85d523e9ab48e6f61b9a70fba57e7a0698de Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Thu, 11 Sep 2025 09:15:02 -0700 Subject: [PATCH 5/6] make lint --- exporter/awsxrayexporter/internal/translator/segment_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exporter/awsxrayexporter/internal/translator/segment_test.go b/exporter/awsxrayexporter/internal/translator/segment_test.go index 0b97013044843..8739899bf840e 100644 --- a/exporter/awsxrayexporter/internal/translator/segment_test.go +++ b/exporter/awsxrayexporter/internal/translator/segment_test.go @@ -1180,7 +1180,7 @@ func TestProducerSpanNonAwsRemoteServiceName(t *testing.T) { spanName := "my-topic send" parentSpanID := newSegmentID() attributes := make(map[string]any) - attributes[conventions.AttributePeerService] = "ProducerService" + attributes[string(conventionsv112.PeerServiceKey)] = "ProducerService" resource := constructDefaultResource() span := constructProducerSpan(parentSpanID, spanName, ptrace.StatusCodeOk, "OK", attributes) @@ -1322,7 +1322,7 @@ func validateLocalRootSegmentTypeDependencySubsegment(t *testing.T, segment *aws assert.Equal(t, "myAnnotationValue", segment.Annotations["myAnnotationKey"]) assert.Len(t, segment.Metadata["default"], 30) - assert.Equal(t, "receive", segment.Metadata["default"][conventions.AttributeMessagingOperation]) + assert.Equal(t, "receive", segment.Metadata["default"][string(conventionsv112.MessagingOperationKey)]) assert.Equal(t, "LOCAL_ROOT", segment.Metadata["default"][awsSpanKind]) assert.Equal(t, "myRemoteOperation", segment.Metadata["default"][awsRemoteOperation]) assert.Equal(t, "myTarget", segment.Metadata["default"][remoteTarget]) From 7ebdc943e4c5514dadb6e52b863566f86a5d6164 Mon Sep 17 00:00:00 2001 From: Eric Zhang Date: Wed, 17 Sep 2025 14:39:14 -0700 Subject: [PATCH 6/6] fix changelog entry --- .chloggen/awsxrayexporter-fix-messaging-tracing.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/awsxrayexporter-fix-messaging-tracing.yaml b/.chloggen/awsxrayexporter-fix-messaging-tracing.yaml index 6c66518847e93..05784e5a6c019 100644 --- a/.chloggen/awsxrayexporter-fix-messaging-tracing.yaml +++ b/.chloggen/awsxrayexporter-fix-messaging-tracing.yaml @@ -1,7 +1,7 @@ # Use this changelog template to create an entry for release notes. # One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' -change_type: +change_type: bug_fix # The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) component: awsxrayexporter