diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs
index 3908224b0a1a1..47677b1f612b5 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs
@@ -50,6 +50,7 @@ public string? Id
public string? TraceStateString { get { throw null; } set { } }
public System.Diagnostics.Activity AddBaggage(string key, string? value) { throw null; }
public System.Diagnostics.Activity AddEvent(System.Diagnostics.ActivityEvent e) { throw null; }
+ public System.Diagnostics.Activity AddLink(System.Diagnostics.ActivityLink link) { throw null; }
public System.Diagnostics.Activity AddTag(string key, string? value) { throw null; }
public System.Diagnostics.Activity AddTag(string key, object? value) { throw null; }
public System.Diagnostics.Activity SetTag(string key, object? value) { throw null; }
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs
index 0605251a93b7a..3a332ec4f1323 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs
@@ -517,6 +517,25 @@ public Activity AddEvent(ActivityEvent e)
return this;
}
+ ///
+ /// Add an to the list.
+ ///
+ /// The to add.
+ /// for convenient chaining.
+ ///
+ /// For contexts that are available during span creation, adding links at span creation is preferred to calling later,
+ /// because head sampling decisions can only consider information present during span creation.
+ ///
+ public Activity AddLink(ActivityLink link)
+ {
+ if (_links != null || Interlocked.CompareExchange(ref _links, new DiagLinkedList(link), null) != null)
+ {
+ _links.Add(link);
+ }
+
+ return this;
+ }
+
///
/// Update the Activity to have baggage with an additional 'key' and value 'value'.
/// This shows up in the enumeration as well as the
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs
index ae3c138e36971..00cb26017a384 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs
@@ -1597,6 +1597,35 @@ public void TestEvent()
Assert.Equal(0, activity.Events.ElementAt(1).Tags.Count());
}
+ [Fact]
+ public void AddLinkTest()
+ {
+ ActivityContext c1 = new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None);
+ ActivityContext c2 = new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None);
+
+ ActivityLink l1 = new ActivityLink(c1);
+ ActivityLink l2 = new ActivityLink(c2, new ActivityTagsCollection()
+ {
+ new KeyValuePair("foo", 99)
+ });
+
+ Activity activity = new Activity("LinkTest");
+ Assert.True(ReferenceEquals(activity, activity.AddLink(l1)));
+ Assert.True(ReferenceEquals(activity, activity.AddLink(l2)));
+
+ // Add a duplicate of l1. The implementation doesn't check for duplicates.
+ Assert.True(ReferenceEquals(activity, activity.AddLink(l1)));
+
+ ActivityLink[] links = activity.Links.ToArray();
+ Assert.Equal(3, links.Length);
+ Assert.Equal(c1, links[0].Context);
+ Assert.Equal(c2, links[1].Context);
+ Assert.Equal(c1, links[2].Context);
+ KeyValuePair tag = links[1].Tags.Single();
+ Assert.Equal("foo", tag.Key);
+ Assert.Equal(99, tag.Value);
+ }
+
[Fact]
public void TestIsAllDataRequested()
{
@@ -2163,12 +2192,14 @@ public void EnumerateLinksTest()
var context1 = new ActivityContext(ActivityTraceId.CreateRandom(), default, ActivityTraceFlags.None);
var context2 = new ActivityContext(ActivityTraceId.CreateRandom(), default, ActivityTraceFlags.None);
+ var context3 = new ActivityContext(ActivityTraceId.CreateRandom(), default, ActivityTraceFlags.None);
a = source.CreateActivity(
name: "Root",
kind: ActivityKind.Internal,
parentContext: default,
links: new[] { new ActivityLink(context1), new ActivityLink(context2) });
+ a.AddLink(new ActivityLink(context3));
Assert.NotNull(a);
@@ -2182,6 +2213,9 @@ public void EnumerateLinksTest()
Assert.True(enumerator.MoveNext());
Assert.Equal(context2.TraceId, enumerator.Current.Context.TraceId);
values.Add(enumerator.Current);
+ Assert.True(enumerator.MoveNext());
+ Assert.Equal(context3.TraceId, enumerator.Current.Context.TraceId);
+ values.Add(enumerator.Current);
Assert.False(enumerator.MoveNext());
Assert.Equal(a.Links, values);