From ccc44f0c1e03bda047b90f2452e6babbf9924cb3 Mon Sep 17 00:00:00 2001 From: linfn Date: Thu, 11 May 2023 12:43:09 +0800 Subject: [PATCH] [receiver/skywalking]: fix parentSpanId lost when crossing segments --- .../skywalkingproto_to_traces.go | 8 ++++- .../skywalkingproto_to_traces_test.go | 35 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/receiver/skywalkingreceiver/skywalkingproto_to_traces.go b/receiver/skywalkingreceiver/skywalkingproto_to_traces.go index efdc7f881fde2..f1a104f14e013 100644 --- a/receiver/skywalkingreceiver/skywalkingproto_to_traces.go +++ b/receiver/skywalkingreceiver/skywalkingproto_to_traces.go @@ -117,9 +117,15 @@ func swSpanToSpan(traceID string, segmentID string, span *agentV3.SpanObject, de // so use segmentId to convert to an unique otel-span dest.SetSpanID(segmentIDToSpanID(segmentID, uint32(span.GetSpanId()))) - // parent spanid = -1, means(root span) no parent span in skywalking,so just make otlp's parent span id empty. + // parent spanid = -1, means(root span) no parent span in current skywalking segment, so it is necessary to search for the parent segment. if span.ParentSpanId != -1 { dest.SetParentSpanID(segmentIDToSpanID(segmentID, uint32(span.GetParentSpanId()))) + } else { + // TODO: SegmentReference references usually have only one element, but in batch consumer case, such as in MQ or async batch process, it could be multiple. + // We only handle one element for now. + if len(span.Refs) == 1 { + dest.SetParentSpanID(segmentIDToSpanID(span.Refs[0].GetParentTraceSegmentId(), uint32(span.Refs[0].GetParentSpanId()))) + } } dest.SetName(span.OperationName) diff --git a/receiver/skywalkingreceiver/skywalkingproto_to_traces_test.go b/receiver/skywalkingreceiver/skywalkingproto_to_traces_test.go index 5262a32be43e5..b4f93d6181d42 100644 --- a/receiver/skywalkingreceiver/skywalkingproto_to_traces_test.go +++ b/receiver/skywalkingreceiver/skywalkingproto_to_traces_test.go @@ -309,6 +309,41 @@ func Test_segmentIdToSpanId_Unique(t *testing.T) { assert.NotEqual(t, results[0], results[1]) } +func Test_swSpanToSpan_ParentSpanId(t *testing.T) { + type args struct { + span *agentV3.SpanObject + } + tests := []struct { + name string + args args + want pcommon.SpanID + }{ + { + name: "mock-sw-span-with-parent-segment", + args: args{span: &agentV3.SpanObject{ + ParentSpanId: -1, + Refs: []*agentV3.SegmentReference{{ + ParentTraceSegmentId: "4f2f27748b8e44ecaf18fe0347194e86.33.16560607369950066", + ParentSpanId: 123, + }}}}, + want: [8]byte{233, 196, 85, 168, 37, 66, 48, 106}, + }, + { + name: "mock-sw-span-without-parent-segment", + args: args{span: &agentV3.SpanObject{Refs: []*agentV3.SegmentReference{{ + ParentSpanId: -1, + }}}}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dest := ptrace.NewSpan() + swSpanToSpan("de5980b8-fce3-4a37-aab9-b4ac3af7eedd", "", tt.args.span, dest) + assert.Equal(t, tt.want, dest.ParentSpanID()) + }) + } +} + func generateTracesOneEmptyResourceSpans() ptrace.Span { td := ptrace.NewTraces() resourceSpan := td.ResourceSpans().AppendEmpty()