Skip to content

Commit 77e73ce

Browse files
Introducing AddLink method in TelemetrySpan (#6305)
Co-authored-by: Alan West <[email protected]>
1 parent 1544659 commit 77e73ce

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
OpenTelemetry.Trace.TelemetrySpan.AddLink(OpenTelemetry.Trace.SpanContext spanContext) -> OpenTelemetry.Trace.TelemetrySpan!
2+
OpenTelemetry.Trace.TelemetrySpan.AddLink(OpenTelemetry.Trace.SpanContext spanContext, OpenTelemetry.Trace.SpanAttributes? attributes) -> OpenTelemetry.Trace.TelemetrySpan!

src/OpenTelemetry.Api/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ Notes](../../RELEASENOTES.md).
66

77
## Unreleased
88

9+
* Added `AddLink(SpanContext, SpanAttributes?)` to `TelemetrySpan` to support
10+
linking spans and associating optional attributes for advanced trace relationships.
11+
([#6305](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6305))
12+
913
## 1.12.0
1014

1115
Released 2025-Apr-29

src/OpenTelemetry.Api/Trace/TelemetrySpan.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,31 @@ public TelemetrySpan AddEvent(string name, DateTimeOffset timestamp, SpanAttribu
226226
return this;
227227
}
228228

229+
/// <summary>
230+
/// Adds a link to another span.
231+
/// </summary>
232+
/// <param name="spanContext">Span context to be linked.</param>
233+
/// <returns>The <see cref="TelemetrySpan"/> instance for chaining.</returns>
234+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
235+
public TelemetrySpan AddLink(SpanContext spanContext)
236+
{
237+
this.AddLinkInternal(spanContext.ActivityContext);
238+
return this;
239+
}
240+
241+
/// <summary>
242+
/// Adds a link to another span.
243+
/// </summary>
244+
/// <param name="spanContext">Span context to be linked.</param>
245+
/// <param name="attributes">Attributes for the link.</param>
246+
/// <returns>The <see cref="TelemetrySpan"/> instance for chaining.</returns>
247+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
248+
public TelemetrySpan AddLink(SpanContext spanContext, SpanAttributes? attributes)
249+
{
250+
this.AddLinkInternal(spanContext.ActivityContext, attributes?.Attributes);
251+
return this;
252+
}
253+
229254
/// <summary>
230255
/// End the span.
231256
/// </summary>
@@ -342,4 +367,12 @@ private void AddEventInternal(string name, DateTimeOffset timestamp = default, A
342367
this.Activity!.AddEvent(new ActivityEvent(name, timestamp, tags));
343368
}
344369
}
370+
371+
private void AddLinkInternal(ActivityContext context, ActivityTagsCollection? tags = null)
372+
{
373+
if (this.IsRecording)
374+
{
375+
this.Activity!.AddLink(new ActivityLink(context, tags));
376+
}
377+
}
345378
}

test/OpenTelemetry.Api.Tests/Trace/TelemetrySpanTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,65 @@ public void ParentIds()
7272

7373
Assert.Equal(parentSpan.Context.SpanId, childSpan.ParentSpanId);
7474
}
75+
76+
[Fact]
77+
public void CheckAddLinkData()
78+
{
79+
using var activity = new Activity("test-activity");
80+
activity.Start();
81+
using var span = new TelemetrySpan(activity);
82+
83+
var traceId = ActivityTraceId.CreateRandom();
84+
var spanId = ActivitySpanId.CreateRandom();
85+
var context = new SpanContext(traceId, spanId, ActivityTraceFlags.Recorded);
86+
87+
span.AddLink(context);
88+
89+
Assert.Single(activity.Links);
90+
var link = activity.Links.First();
91+
Assert.Equal(traceId, link.Context.TraceId);
92+
Assert.Equal(spanId, link.Context.SpanId);
93+
Assert.Null(link.Tags);
94+
}
95+
96+
[Fact]
97+
public void CheckAddLinkAttributes()
98+
{
99+
using var activity = new Activity("test-activity");
100+
activity.Start();
101+
using var span = new TelemetrySpan(activity);
102+
103+
var traceId = ActivityTraceId.CreateRandom();
104+
var spanId = ActivitySpanId.CreateRandom();
105+
var context = new SpanContext(traceId, spanId, ActivityTraceFlags.Recorded);
106+
107+
var attributes = new SpanAttributes();
108+
attributes.Add("key1", "value1");
109+
110+
span.AddLink(context, attributes);
111+
112+
Assert.Single(activity.Links);
113+
var link = activity.Links.First();
114+
Assert.NotNull(link.Tags);
115+
Assert.Single(link.Tags);
116+
var tag = link.Tags.First();
117+
Assert.Equal("key1", tag.Key);
118+
Assert.Equal("value1", tag.Value);
119+
}
120+
121+
[Fact]
122+
public void CheckAddLinkNotRecording()
123+
{
124+
using var activity = new Activity("test-activity");
125+
126+
// Simulate not recording
127+
activity.IsAllDataRequested = false;
128+
using var span = new TelemetrySpan(activity);
129+
130+
var context = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None);
131+
132+
span.AddLink(context, null);
133+
134+
Assert.Empty(activity.Links);
135+
}
75136
}

0 commit comments

Comments
 (0)