Skip to content

Commit bbb4b0c

Browse files
authored
Fix Restoring the Original Activity Parent (#48034)
1 parent 8176a2b commit bbb4b0c

File tree

3 files changed

+78
-8
lines changed

3 files changed

+78
-8
lines changed

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ public partial class Activity : IDisposable
8484
private string? _displayName;
8585
private ActivityStatusCode _statusCode;
8686
private string? _statusDescription;
87+
private Activity? _previousActiveActivity;
8788

8889
/// <summary>
8990
/// Gets status code of the current activity object.
@@ -621,15 +622,15 @@ public Activity Start()
621622
}
622623
else
623624
{
625+
_previousActiveActivity = Current;
624626
if (_parentId == null && _parentSpanId is null)
625627
{
626-
Activity? parent = Current;
627-
if (parent != null)
628+
if (_previousActiveActivity != null)
628629
{
629630
// The parent change should not form a loop. We are actually guaranteed this because
630631
// 1. Un-started activities can't be 'Current' (thus can't be 'parent'), we throw if you try.
631632
// 2. All started activities have a finite parent change (by inductive reasoning).
632-
Parent = parent;
633+
Parent = _previousActiveActivity;
633634
}
634635
}
635636

@@ -686,8 +687,7 @@ public void Stop()
686687
}
687688

688689
Source.NotifyActivityStop(this);
689-
690-
SetCurrent(Parent);
690+
SetCurrent(_previousActiveActivity);
691691
}
692692
}
693693

@@ -1004,6 +1004,7 @@ internal static Activity CreateAndStart(ActivitySource source, string name, Acti
10041004
activity.Source = source;
10051005
activity.Kind = kind;
10061006

1007+
activity._previousActiveActivity = Current;
10071008
if (parentId != null)
10081009
{
10091010
activity._parentId = parentId;
@@ -1022,13 +1023,12 @@ internal static Activity CreateAndStart(ActivitySource source, string name, Acti
10221023
}
10231024
else
10241025
{
1025-
Activity? parent = Current;
1026-
if (parent != null)
1026+
if (activity._previousActiveActivity != null)
10271027
{
10281028
// The parent change should not form a loop. We are actually guaranteed this because
10291029
// 1. Un-started activities can't be 'Current' (thus can't be 'parent'), we throw if you try.
10301030
// 2. All started activities have a finite parent change (by inductive reasoning).
1031-
activity.Parent = parent;
1031+
activity.Parent = activity._previousActiveActivity;
10321032
}
10331033
}
10341034

src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivitySourceTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,42 @@ public void TestAddSamplerAndActivityCreationTags()
845845
}).Dispose();
846846
}
847847

848+
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
849+
public void RestoreOriginalParentTest()
850+
{
851+
RemoteExecutor.Invoke(() =>
852+
{
853+
using ActivitySource source = new ActivitySource("OriginalParentSource");
854+
using ActivityListener listener = new ActivityListener();
855+
856+
listener.ShouldListenTo = (activitySource) => object.ReferenceEquals(source, activitySource);
857+
listener.SampleUsingParentId = (ref ActivityCreationOptions<string> activityOptions) => ActivitySamplingResult.AllData;
858+
listener.Sample = (ref ActivityCreationOptions<ActivityContext> activityOptions) => ActivitySamplingResult.AllData;
859+
ActivitySource.AddActivityListener(listener);
860+
861+
Assert.Null(Activity.Current);
862+
863+
using (Activity c = source.StartActivity("Root"))
864+
{
865+
Assert.NotNull(Activity.Current);
866+
Assert.Equal("Root", Activity.Current.OperationName);
867+
868+
// Create Activity with the parent context to not use Activity.Current as a parent
869+
using (Activity d = source.StartActivity("Child", default, new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), default, default)))
870+
{
871+
Assert.NotNull(Activity.Current);
872+
Assert.Equal("Child", Activity.Current.OperationName);
873+
}
874+
875+
// Now the child activity stopped. We used to restore null to the Activity.Current but now we restore
876+
// the original parent stored in Activity.Current before we started the Activity.
877+
Assert.NotNull(Activity.Current);
878+
Assert.Equal("Root", Activity.Current.OperationName);
879+
}
880+
Assert.Null(Activity.Current);
881+
}).Dispose();
882+
}
883+
848884
public void Dispose() => Activity.Current = null;
849885
}
850886
}

src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,6 +1751,40 @@ public void StructEnumerator_GenericLinkedList()
17511751
Assert.True(method.ReturnType.IsValueType);
17521752
}
17531753

1754+
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
1755+
public void RestoreOriginalParentTest()
1756+
{
1757+
RemoteExecutor.Invoke(() =>
1758+
{
1759+
Assert.Null(Activity.Current);
1760+
1761+
Activity a = new Activity("Root");
1762+
a.Start();
1763+
1764+
Assert.NotNull(Activity.Current);
1765+
Assert.Equal("Root", Activity.Current.OperationName);
1766+
1767+
// Create Activity with the parent context to not use Activity.Current as a parent
1768+
Activity b = new Activity("Child");
1769+
b.SetParentId(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom());
1770+
b.Start();
1771+
1772+
Assert.NotNull(Activity.Current);
1773+
Assert.Equal("Child", Activity.Current.OperationName);
1774+
1775+
b.Stop();
1776+
1777+
// Now the child activity stopped. We used to restore null to the Activity.Current but now we restore
1778+
// the original parent stored in Activity.Current before we started the Activity.
1779+
Assert.NotNull(Activity.Current);
1780+
Assert.Equal("Root", Activity.Current.OperationName);
1781+
1782+
a.Stop();
1783+
Assert.Null(Activity.Current);
1784+
1785+
}).Dispose();
1786+
}
1787+
17541788
public void Dispose()
17551789
{
17561790
Activity.Current = null;

0 commit comments

Comments
 (0)