Skip to content
Open
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
7 changes: 7 additions & 0 deletions internal/aws/xray/testdata/segmentWithParentId.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"trace_id": "1-5f187253-6a106696d56b1f4ef9eba2ed",
"id": "5cc4a447f5d4d696",
"name": "segment",
"start_time": 1595437651.680097,
"parent_id": "bda182a644eee9b3"
}
20 changes: 12 additions & 8 deletions receiver/awsxrayreceiver/internal/translator/translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/hex"
"encoding/json"
"errors"
"strings"

"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/ptrace"
Expand Down Expand Up @@ -65,7 +66,10 @@ func ToTraces(rawSeg []byte, recorder telemetry.Recorder) (ptrace.Traces, int, e
// TraceID of the root segment in because embedded subsegments
// do not have that information, but it's needed after we flatten
// the embedded subsegment to generate independent child spans.
_, err = segToSpans(seg, seg.TraceID, nil, spans)
// Sometimes, subsegments are sent separately in an async workflow,
// check segment type to determine the proper span kind.
isSubsegment := seg.ParentID != nil && seg.Type != nil && strings.EqualFold(*seg.Type, "subsegment")
_, err = segToSpans(seg, seg.TraceID, nil, isSubsegment, spans)
if err != nil {
recorder.RecordSegmentsRejected(count)
return ptrace.Traces{}, count, err
Expand All @@ -74,18 +78,18 @@ func ToTraces(rawSeg []byte, recorder telemetry.Recorder) (ptrace.Traces, int, e
return traceData, count, nil
}

func segToSpans(seg awsxray.Segment, traceID, parentID *string, spans ptrace.SpanSlice) (ptrace.Span, error) {
func segToSpans(seg awsxray.Segment, traceID, parentID *string, isSubsegment bool, spans ptrace.SpanSlice) (ptrace.Span, error) {
span := spans.AppendEmpty()

err := populateSpan(&seg, traceID, parentID, span)
err := populateSpan(&seg, traceID, parentID, isSubsegment, span)
if err != nil {
return ptrace.Span{}, err
}

var populatedChildSpan ptrace.Span
for _, s := range seg.Subsegments {
populatedChildSpan, err = segToSpans(s,
traceID, seg.ID,
traceID, seg.ID, true,
spans)
if err != nil {
return ptrace.Span{}, err
Expand All @@ -109,7 +113,7 @@ func segToSpans(seg awsxray.Segment, traceID, parentID *string, spans ptrace.Spa
return span, nil
}

func populateSpan(seg *awsxray.Segment, traceID, parentID *string, span ptrace.Span) error {
func populateSpan(seg *awsxray.Segment, traceID, parentID *string, isSubsegment bool, span ptrace.Span) error {
attrs := span.Attributes()
attrs.Clear()
attrs.EnsureCapacity(initAttrCapacity)
Expand Down Expand Up @@ -156,11 +160,11 @@ func populateSpan(seg *awsxray.Segment, traceID, parentID *string, span ptrace.S

span.SetTraceID(traceIDBytes)
span.SetSpanID(spanIDBytes)

if !isSubsegment {
span.SetKind(ptrace.SpanKindServer)
}
if parentIDBytes != [8]byte{} {
span.SetParentSpanID(parentIDBytes)
} else {
span.SetKind(ptrace.SpanKindServer)
}

addStartTime(seg.StartTime, span)
Expand Down
43 changes: 43 additions & 0 deletions receiver/awsxrayreceiver/internal/translator/translator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,49 @@ func TestTranslation(t *testing.T) {
assert.NoError(t, ptracetest.CompareResourceSpans(expectedRs, actualRs))
},
},
{
testCase: "TranslateSegmentWithParentId",
samplePath: filepath.Join("../../../../internal/aws/xray", "testdata", "segmentWithParentId.txt"),
expectedResourceAttrs: func(seg *awsxray.Segment) map[string]any {
return map[string]any{
conventions.AttributeServiceName: *seg.Name,
conventions.AttributeCloudProvider: "unknown",
}
},
expectedRecord: xray.TelemetryRecord{
SegmentsReceivedCount: aws.Int64(1),
SegmentsRejectedCount: aws.Int64(0),
},
propsPerSpan: func(_ *testing.T, _ string, seg *awsxray.Segment) []perSpanProperties {
attrs := pcommon.NewMap()
res := perSpanProperties{
traceID: *seg.TraceID,
spanID: *seg.ID,
parentSpanID: seg.ParentID,
name: *seg.Name,
startTimeSec: *seg.StartTime,
endTimeSec: seg.EndTime,
spanKind: ptrace.SpanKindServer,
spanStatus: spanSt{
code: ptrace.StatusCodeUnset,
},
attrs: attrs,
}
return []perSpanProperties{res}
// return nil
},
verification: func(testCase string,
_ *awsxray.Segment,
expectedRs ptrace.ResourceSpans, actualTraces ptrace.Traces, err error,
) {
assert.NoError(t, err, testCase+": translation should've succeeded")
assert.Equal(t, 1, actualTraces.ResourceSpans().Len(),
testCase+": one segment should translate to 1 ResourceSpans")

actualRs := actualTraces.ResourceSpans().At(0)
assert.NoError(t, ptracetest.CompareResourceSpans(expectedRs, actualRs))
},
},
{
testCase: "TranslateJsonUnmarshallFailed",
expectedUnmarshallFailure: true,
Expand Down
Loading