Skip to content

Commit c00a51a

Browse files
amanakinMrAlias
andauthored
Record links with empty span context (open-telemetry#5315)
* record links with empty span context * add global trace state * fix test comments and changelog --------- Co-authored-by: Tyler Yahn <[email protected]>
1 parent 9f1de84 commit c00a51a

File tree

3 files changed

+92
-6
lines changed

3 files changed

+92
-6
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2424
- De-duplicate map attributes added to a `Record` in `go.opentelemetry.io/otel/sdk/log`. (#5230)
2525
- The `go.opentelemetry.io/otel/exporters/stdout/stdoutlog` exporter won't print `AttributeValueLengthLimit` and `AttributeCountLimit` fields now, instead it prints the `DroppedAttributes` field. (#5272)
2626
- Improved performance in the `Stringer` implementation of `go.opentelemetry.io/otel/baggage.Member` by reducing the number of allocations. (#5286)
27+
- The `Span` in `go.opentelemetry.io/otel/sdk/trace` will record links without span context if either non-empty `TraceState` or attributes are provided. (#5315)
2728

2829
### Fixed
2930

sdk/trace/span.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,11 @@ func (s *recordingSpan) Resource() *resource.Resource {
630630
}
631631

632632
func (s *recordingSpan) AddLink(link trace.Link) {
633-
if !s.IsRecording() || !link.SpanContext.IsValid() {
633+
if !s.IsRecording() {
634+
return
635+
}
636+
if !link.SpanContext.IsValid() && len(link.Attributes) == 0 &&
637+
link.SpanContext.TraceState().Len() == 0 {
634638
return
635639
}
636640

sdk/trace/trace_test.go

+86-5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ var (
4747
tid trace.TraceID
4848
sid trace.SpanID
4949
sc trace.SpanContext
50+
ts trace.TraceState
5051

5152
handler = &storingHandler{}
5253
)
@@ -59,6 +60,7 @@ func init() {
5960
SpanID: sid,
6061
TraceFlags: 0x1,
6162
})
63+
ts, _ = trace.ParseTraceState("k=v")
6264

6365
otel.SetErrorHandler(handler)
6466
}
@@ -330,10 +332,6 @@ func TestStartSpanWithParent(t *testing.T) {
330332
t.Error(err)
331333
}
332334

333-
ts, err := trace.ParseTraceState("k=v")
334-
if err != nil {
335-
t.Error(err)
336-
}
337335
sc2 := sc.WithTraceState(ts)
338336
_, s3 := tr.Start(trace.ContextWithRemoteSpanContext(ctx, sc2), "span3-sampled-parent2")
339337
if err := checkChild(t, sc2, s3); err != nil {
@@ -1934,7 +1932,6 @@ func TestSpanAddLink(t *testing.T) {
19341932
attrLinkCountLimit: 128,
19351933
link: trace.Link{
19361934
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{}), SpanID: [8]byte{}}),
1937-
Attributes: []attribute.KeyValue{{Key: "k1", Value: attribute.StringValue("v1")}},
19381935
},
19391936
want: &snapshot{
19401937
name: "span0",
@@ -2002,6 +1999,50 @@ func TestSpanAddLink(t *testing.T) {
20021999
instrumentationScope: instrumentation.Scope{Name: "AddLinkWithMoreAttributesThanLimit"},
20032000
},
20042001
},
2002+
{
2003+
name: "AddLinkWithAttributesEmptySpanContext",
2004+
attrLinkCountLimit: 128,
2005+
link: trace.Link{
2006+
Attributes: []attribute.KeyValue{{Key: "k1", Value: attribute.StringValue("v1")}},
2007+
},
2008+
want: &snapshot{
2009+
name: "span0",
2010+
spanContext: trace.NewSpanContext(trace.SpanContextConfig{
2011+
TraceID: tid,
2012+
TraceFlags: 0x1,
2013+
}),
2014+
parent: sc.WithRemote(true),
2015+
links: []Link{
2016+
{
2017+
Attributes: []attribute.KeyValue{{Key: "k1", Value: attribute.StringValue("v1")}},
2018+
},
2019+
},
2020+
spanKind: trace.SpanKindInternal,
2021+
instrumentationScope: instrumentation.Scope{Name: "AddLinkWithAttributesEmptySpanContext"},
2022+
},
2023+
},
2024+
{
2025+
name: "AddLinkWithTraceStateEmptySpanContext",
2026+
attrLinkCountLimit: 128,
2027+
link: trace.Link{
2028+
SpanContext: trace.SpanContext{}.WithTraceState(ts),
2029+
},
2030+
want: &snapshot{
2031+
name: "span0",
2032+
spanContext: trace.NewSpanContext(trace.SpanContextConfig{
2033+
TraceID: tid,
2034+
TraceFlags: 0x1,
2035+
}),
2036+
parent: sc.WithRemote(true),
2037+
links: []Link{
2038+
{
2039+
SpanContext: trace.SpanContext{}.WithTraceState(ts),
2040+
},
2041+
},
2042+
spanKind: trace.SpanKindInternal,
2043+
instrumentationScope: instrumentation.Scope{Name: "AddLinkWithTraceStateEmptySpanContext"},
2044+
},
2045+
},
20052046
}
20062047

20072048
for _, tc := range tests {
@@ -2026,3 +2067,43 @@ func TestSpanAddLink(t *testing.T) {
20262067
})
20272068
}
20282069
}
2070+
2071+
func TestAddLinkToNonRecordingSpan(t *testing.T) {
2072+
te := NewTestExporter()
2073+
sl := NewSpanLimits()
2074+
tp := NewTracerProvider(
2075+
WithSpanLimits(sl),
2076+
WithSyncer(te),
2077+
WithResource(resource.Empty()),
2078+
)
2079+
2080+
attrs := []attribute.KeyValue{{Key: "k", Value: attribute.StringValue("v")}}
2081+
2082+
span := startSpan(tp, "AddLinkToNonRecordingSpan")
2083+
_, err := endSpan(te, span)
2084+
require.NoError(t, err)
2085+
2086+
// Add link to ended, non-recording, span. The link should be dropped.
2087+
span.AddLink(trace.Link{
2088+
SpanContext: sc,
2089+
Attributes: attrs,
2090+
})
2091+
2092+
require.Equal(t, 1, te.Len())
2093+
got := te.Spans()[0]
2094+
want := &snapshot{
2095+
name: "span0",
2096+
spanContext: trace.NewSpanContext(trace.SpanContextConfig{
2097+
TraceID: tid,
2098+
TraceFlags: 0x1,
2099+
}),
2100+
parent: sc.WithRemote(true),
2101+
links: nil,
2102+
spanKind: trace.SpanKindInternal,
2103+
instrumentationScope: instrumentation.Scope{Name: "AddLinkToNonRecordingSpan"},
2104+
}
2105+
2106+
if diff := cmpDiff(got, want); diff != "" {
2107+
t.Errorf("AddLinkToNonRecordingSpan: -got +want %s", diff)
2108+
}
2109+
}

0 commit comments

Comments
 (0)