Skip to content

Commit 8c21bab

Browse files
authored
[exporter/awsxray] Support setting inProgress segment-field in X-Ray Exporter (#43962)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description When using OTel Collector with `X-Ray Receiver/Exporter`, X-Ray Segment gets converted into OpenTelemetry Span (via X-Ray Receiver) and then later gets converted into X-Ray Segment (via X-Ray Exporter). In X-Ray Receiver, the `in_progress` Segment field attribute is explicitly converted into the `aws.xray.inprogress` attribute. - https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.138.0/receiver/awsxrayreceiver/internal/translator/translator.go#L169 In X-Ray Exporter, the `aws.xray.inprogress` attribute **is not** converted back into the `in_progress` Segment field: - https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.138.0/exporter/awsxrayexporter/internal/translator/segment.go#L336-L350 Therefore the `in_progress` functionality does not function as it was intended as it is now part of metadata instead of being a Segment field. The Segment doesn't have the ability to be updated later since it isn't correctly labeled as `in_progress` in X-Ray. This PR fixes this issue by ensuring that `in_progress` is converted back into a Segment field if the original Segment ingested by X-Ray Receiver had `in_progress` set. Furthermore, if `in_progress` is set, then `end_time` **shouldn't** be set. <!-- Issue number (e.g. #1234) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes #44001 <!--Describe what testing was performed and which tests were added.--> #### Testing Tested with OCB: `builder-config.yaml`: ```yaml dist: name: otelcol-dev-0.138.0 description: Basic OTel Collector distribution for Developers output_path: ./otelcol-dev-prod-0.138.0 otelcol_version: 0.138.0 exporters: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/awsxrayexporter v0.138.0 receivers: - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.138.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/awsxrayreceiver v0.138.0 extensions: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/awsproxy v0.138.0 replaces: - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/awsxrayexporter v0.138.0 => github.com/jj22ee/opentelemetry-collector-contrib/exporter/awsxrayexporter v0.138.1 ``` config.yaml ```yaml extensions: awsproxy: local_mode: true region: 'us-west-2' #health_check: receivers: awsxray: transport: udp proxy_server: tls: insecure: false server_name_override: "" region: 'us-west-2' role_arn: "" aws_endpoint: "" local_mode: true otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: awsxray: region: 'us-west-2' index_all_attributes: true service: pipelines: traces: receivers: [awsxray, otlp] exporters: [awsxray] extensions: [awsproxy] #[health_check] telemetry: logs: level: debug ``` Send segment to OTel Collector: > `cat sample-trace.json | nc -u 127.0.0.1 2000` sample-trace.json: ``` {"format":"json","version":1} {"type":"segment","trace_id":"1-64d8bfaf-fd72e26886b3fdd3a272224e","id":"6222467a3d841238","start_time":1759136781.313,"in_progress":true,"name":"testName","user":"213456","origin":"AWS::EC2::Instance","namespace":"aws","aws":{"account_id":"123456789012"}} ``` Result before fix: - X-Ray Segment in AWS X-Ray has `in_progress` as Segment metadata, `end_time` is set. Result after fix: - X-Ray Segment in AWS X-Ray has `in_progress` as a Segment field, `end_time` isn't set. <!--Describe the documentation added.--> #### Documentation <!--Please delete paragraphs that you did not use before submitting.-->
1 parent feb7a48 commit 8c21bab

File tree

3 files changed

+82
-4
lines changed

3 files changed

+82
-4
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
2+
change_type: 'bug_fix'
3+
4+
# The name of the component, or a single word describing the area of concern, (e.g. receiver/filelog)
5+
component: 'exporter/awsxray'
6+
7+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
8+
note: "Fix conversion of the inProgress attribute into a Segment field instead of metadata"
9+
10+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
11+
issues: [44001]
12+
13+
# (Optional) One or more lines of additional information to render under the primary note.
14+
# These lines will be padded with 2 spaces and then inserted directly into the document.
15+
# Use pipe (|) for multiline entries.
16+
subtext:
17+
18+
# If your change doesn't affect end users or the exported elements of any package,
19+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: []

exporter/awsxrayexporter/internal/translator/segment.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ func MakeSegment(span ptrace.Span, resource pcommon.Resource, indexedAttrs []str
334334
attributes := span.Attributes()
335335

336336
var (
337-
startTime = timestampToFloatSeconds(span.StartTimestamp())
338-
endTime = timestampToFloatSeconds(span.EndTimestamp())
337+
startTimePtr = awsP.Float64(timestampToFloatSeconds(span.StartTimestamp()))
338+
endTimePtr, inProgress = makeEndTimeAndInProgress(span, attributes)
339339
httpfiltered, http = makeHTTP(span)
340340
isError, isFault, isThrottle, causefiltered, cause = makeCause(span, httpfiltered, resource)
341341
origin = determineAwsOrigin(resource)
@@ -456,8 +456,9 @@ func MakeSegment(span ptrace.Span, resource pcommon.Resource, indexedAttrs []str
456456
ID: awsxray.String(traceutil.SpanIDToHexOrEmptyString(span.SpanID())),
457457
TraceID: awsxray.String(traceID),
458458
Name: awsxray.String(name),
459-
StartTime: awsP.Float64(startTime),
460-
EndTime: awsP.Float64(endTime),
459+
StartTime: startTimePtr,
460+
EndTime: endTimePtr,
461+
InProgress: inProgress,
461462
ParentID: awsxray.String(traceutil.SpanIDToHexOrEmptyString(span.ParentSpanID())),
462463
Fault: awsP.Bool(isFault),
463464
Error: awsP.Bool(isError),
@@ -756,6 +757,17 @@ func fixAnnotationKey(key string) string {
756757
}, key)
757758
}
758759

760+
func makeEndTimeAndInProgress(span ptrace.Span, attributes pcommon.Map) (*float64, *bool) {
761+
if inProgressAttr, ok := attributes.Get(awsxray.AWSXRayInProgressAttribute); ok && inProgressAttr.Type() == pcommon.ValueTypeBool {
762+
inProgressVal := inProgressAttr.Bool()
763+
attributes.Remove(awsxray.AWSXRayInProgressAttribute)
764+
if inProgressVal {
765+
return nil, &inProgressVal
766+
}
767+
}
768+
return awsP.Float64(timestampToFloatSeconds(span.EndTimestamp())), nil
769+
}
770+
759771
func trimAwsSdkPrefix(name string, span ptrace.Span) string {
760772
if isAwsSdkSpan(span) {
761773
if strings.HasPrefix(name, "AWS.SDK.") {

exporter/awsxrayexporter/internal/translator/segment_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,11 @@ func TestLocalRootConsumer(t *testing.T) {
14441444
// Checks these values are the same for both
14451445
assert.Equal(t, segments[0].StartTime, segments[1].StartTime)
14461446
assert.Equal(t, segments[0].EndTime, segments[1].EndTime)
1447+
1448+
// Check that segment EndTime matches span's EndTime
1449+
expectedEndTime := float64(span.EndTimestamp()) / float64(time.Second)
1450+
assert.Equal(t, expectedEndTime, *segments[0].EndTime)
1451+
assert.Equal(t, expectedEndTime, *segments[1].EndTime)
14471452
}
14481453

14491454
func TestNonLocalRootConsumerProcess(t *testing.T) {
@@ -1967,6 +1972,8 @@ func constructSpanAttributes(attributes map[string]any) pcommon.Map {
19671972
attrs.PutInt(key, int64(cast))
19681973
case int64:
19691974
attrs.PutInt(key, cast)
1975+
case bool:
1976+
attrs.PutBool(key, cast)
19701977
case []string:
19711978
slice := attrs.PutEmptySlice(key)
19721979
for _, v := range cast {
@@ -2042,6 +2049,40 @@ func constructTimedEventsWithSentMessageEvent(tm pcommon.Timestamp) ptrace.SpanE
20422049
}
20432050

20442051
// newTraceID generates a new valid X-Ray TraceID
2052+
func TestSpanWithInProgressTrue(t *testing.T) {
2053+
spanName := "/api/test"
2054+
parentSpanID := newSegmentID()
2055+
attributes := make(map[string]any)
2056+
attributes[awsxray.AWSXRayInProgressAttribute] = true
2057+
resource := constructDefaultResource()
2058+
span := constructServerSpan(parentSpanID, spanName, ptrace.StatusCodeOk, "OK", attributes)
2059+
2060+
segment, _ := MakeSegment(span, resource, nil, false, nil, false)
2061+
2062+
assert.NotNil(t, segment)
2063+
assert.NotNil(t, segment.InProgress)
2064+
assert.True(t, *segment.InProgress)
2065+
assert.Nil(t, segment.EndTime)
2066+
assert.Nil(t, segment.Metadata["default"][awsxray.AWSXRayInProgressAttribute])
2067+
}
2068+
2069+
func TestSpanWithInProgressFalse(t *testing.T) {
2070+
spanName := "/api/test"
2071+
parentSpanID := newSegmentID()
2072+
attributes := make(map[string]any)
2073+
attributes[awsxray.AWSXRayInProgressAttribute] = false
2074+
resource := constructDefaultResource()
2075+
span := constructServerSpan(parentSpanID, spanName, ptrace.StatusCodeOk, "OK", attributes)
2076+
2077+
segment, _ := MakeSegment(span, resource, nil, false, nil, false)
2078+
2079+
assert.NotNil(t, segment)
2080+
assert.Nil(t, segment.InProgress)
2081+
assert.NotNil(t, segment.EndTime)
2082+
assert.Empty(t, segment.Annotations)
2083+
assert.Nil(t, segment.Metadata["default"][awsxray.AWSXRayInProgressAttribute])
2084+
}
2085+
20452086
func newTraceID() pcommon.TraceID {
20462087
var r [16]byte
20472088
epoch := time.Now().Unix()

0 commit comments

Comments
 (0)