Skip to content

Commit 2eaf6dd

Browse files
Copilotstephentoubtarekgh
authored
Add DebuggerDisplay and DebuggerTypeProxy to Activity and related types (#121054)
--------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: stephentoub <[email protected]> Co-authored-by: tarekgh <[email protected]>
1 parent 82ce59a commit 2eaf6dd

File tree

7 files changed

+104
-0
lines changed

7 files changed

+104
-0
lines changed

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ internal ActivityChangedEventArgs(Activity? previous, Activity? current)
5454
/// but the exception is suppressed, and the operation does something reasonable (typically
5555
/// doing nothing).
5656
/// </summary>
57+
[DebuggerDisplay("{DebuggerDisplayString,nq}")]
58+
[DebuggerTypeProxy(typeof(ActivityDebuggerProxy))]
5759
public partial class Activity : IDisposable
5860
{
5961
#pragma warning disable CA1825 // Array.Empty<T>() doesn't exist in all configurations
@@ -1839,6 +1841,15 @@ public override string ToString()
18391841
}
18401842
}
18411843

1844+
private string DebuggerDisplayString
1845+
{
1846+
get
1847+
{
1848+
string? id = Id;
1849+
return $"OperationName = {OperationName}, Id = {(id is not null ? id : "(null)")}";
1850+
}
1851+
}
1852+
18421853
[Flags]
18431854
private enum State : byte
18441855
{
@@ -2168,4 +2179,30 @@ public void CopyTo(Span<byte> destination)
21682179
ActivityTraceId.SetSpanFromHexChars(ToHexString().AsSpan(), destination);
21692180
}
21702181
}
2182+
2183+
internal sealed class ActivityDebuggerProxy(Activity activity)
2184+
{
2185+
public ActivityTraceFlags ActivityTraceFlags => activity.ActivityTraceFlags;
2186+
public List<KeyValuePair<string, string?>> Baggage => new List<KeyValuePair<string, string?>>(activity.Baggage);
2187+
public ActivityContext Context => activity.Context;
2188+
public string DisplayName => activity.DisplayName;
2189+
public TimeSpan Duration => activity.Duration;
2190+
public List<ActivityEvent> Events => new List<ActivityEvent>(activity.Events);
2191+
public bool HasRemoteParent => activity.HasRemoteParent;
2192+
public string? Id => activity.Id;
2193+
public ActivityKind Kind => activity.Kind;
2194+
public List<ActivityLink> Links => new List<ActivityLink>(activity.Links);
2195+
public string OperationName => activity.OperationName;
2196+
public Activity? Parent => activity.Parent;
2197+
public string? ParentId => activity.ParentId;
2198+
public ActivitySpanId ParentSpanId => activity.ParentSpanId;
2199+
public ActivitySource Source => activity.Source;
2200+
public ActivitySpanId SpanId => activity.SpanId;
2201+
public DateTime StartTimeUtc => activity.StartTimeUtc;
2202+
public ActivityStatusCode Status => activity.Status;
2203+
public string? StatusDescription => activity.StatusDescription;
2204+
public List<KeyValuePair<string, object?>> TagObjects => new List<KeyValuePair<string, object?>>(activity.TagObjects);
2205+
public ActivityTraceId TraceId => activity.TraceId;
2206+
public string? TraceStateString => activity.TraceStateString;
2207+
}
21712208
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace System.Diagnostics
1010
/// ActivityContext representation conforms to the w3c TraceContext specification. It contains two identifiers
1111
/// a TraceId and a SpanId - along with a set of common TraceFlags and system-specific TraceState values.
1212
/// </summary>
13+
[DebuggerDisplay("TraceId = {TraceId}, SpanId = {SpanId}, TraceFlags = {TraceFlags}")]
1314
public readonly partial struct ActivityContext : IEquatable<ActivityContext>
1415
{
1516
/// <summary>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace System.Diagnostics
99
/// <summary>
1010
/// A text annotation associated with a collection of tags.
1111
/// </summary>
12+
[DebuggerDisplay("Name = {Name}, Timestamp = {Timestamp}")]
1213
public readonly struct ActivityEvent
1314
{
1415
private static readonly IEnumerable<KeyValuePair<string, object?>> s_emptyTags = Array.Empty<KeyValuePair<string, object?>>();

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace System.Diagnostics
1212
/// Links can be used to represent batched operations where a Activity was initiated by multiple initiating Activities,
1313
/// each representing a single incoming item being processed in the batch.
1414
/// </summary>
15+
[DebuggerDisplay("{DebuggerDisplayString,nq}")]
1516
public readonly partial struct ActivityLink : IEquatable<ActivityLink>
1617
{
1718
private readonly Activity.TagsLinkedList? _tags;
@@ -38,6 +39,8 @@ public ActivityLink(ActivityContext context, ActivityTagsCollection? tags = null
3839
/// </summary>
3940
public IEnumerable<KeyValuePair<string, object?>>? Tags => _tags;
4041

42+
private string DebuggerDisplayString => $"TraceId = {Context.TraceId}, SpanId = {Context.SpanId}";
43+
4144
public override bool Equals([NotNullWhen(true)] object? obj) => (obj is ActivityLink link) && this.Equals(link);
4245

4346
public bool Equals(ActivityLink value) => Context == value.Context && value.Tags == Tags;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
namespace System.Diagnostics
1010
{
11+
[DebuggerDisplay("Name = {Name}")]
1112
public sealed class ActivitySource : IDisposable
1213
{
1314
private static readonly SynchronizedList<ActivitySource> s_activeSources = new SynchronizedList<ActivitySource>();

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2548,5 +2548,65 @@ public void OnError(Exception error) { }
25482548
}
25492549

25502550
private const int MaxClockErrorMSec = 20;
2551+
2552+
[Fact]
2553+
public void TestActivityDebuggerDisplay()
2554+
{
2555+
Activity activity = new Activity("TestOperation");
2556+
activity.Start();
2557+
2558+
string debuggerDisplay = DebuggerAttributes.ValidateDebuggerDisplayReferences(activity);
2559+
Assert.Contains("OperationName = TestOperation", debuggerDisplay);
2560+
Assert.Contains("Id =", debuggerDisplay);
2561+
2562+
activity.Stop();
2563+
}
2564+
2565+
[Fact]
2566+
public void TestActivityDebuggerProxy()
2567+
{
2568+
Activity activity = new Activity("TestOperation");
2569+
activity.SetTag("key1", "value1");
2570+
activity.SetTag("key2", 42);
2571+
activity.SetBaggage("baggage1", "baggageValue1");
2572+
activity.AddEvent(new ActivityEvent("TestEvent"));
2573+
activity.Start();
2574+
2575+
DebuggerAttributes.ValidateDebuggerTypeProxyProperties(activity);
2576+
2577+
activity.Stop();
2578+
}
2579+
2580+
[Fact]
2581+
public void TestActivityContextDebuggerDisplay()
2582+
{
2583+
ActivityTraceId traceId = ActivityTraceId.CreateRandom();
2584+
ActivitySpanId spanId = ActivitySpanId.CreateRandom();
2585+
ActivityContext context = new ActivityContext(traceId, spanId, ActivityTraceFlags.Recorded);
2586+
2587+
string debuggerDisplay = DebuggerAttributes.ValidateDebuggerDisplayReferences(context);
2588+
Assert.NotNull(debuggerDisplay);
2589+
}
2590+
2591+
[Fact]
2592+
public void TestActivityLinkDebuggerDisplay()
2593+
{
2594+
ActivityTraceId traceId = ActivityTraceId.CreateRandom();
2595+
ActivitySpanId spanId = ActivitySpanId.CreateRandom();
2596+
ActivityContext context = new ActivityContext(traceId, spanId, ActivityTraceFlags.Recorded);
2597+
ActivityLink link = new ActivityLink(context);
2598+
2599+
DebuggerAttributes.ValidateDebuggerDisplayReferences(link);
2600+
}
2601+
2602+
[Fact]
2603+
public void TestActivityEventDebuggerDisplay()
2604+
{
2605+
ActivityEvent activityEvent = new ActivityEvent("TestEvent");
2606+
2607+
string debuggerDisplay = DebuggerAttributes.ValidateDebuggerDisplayReferences(activityEvent);
2608+
Assert.Contains("Name = \"TestEvent\"", debuggerDisplay);
2609+
Assert.Contains("Timestamp =", debuggerDisplay);
2610+
}
25512611
}
25522612
}

src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
</ItemGroup>
2424

2525
<ItemGroup>
26+
<Compile Include="$(CommonTestPath)System\Diagnostics\DebuggerAttributes.cs" Link="Common\System\Diagnostics\DebuggerAttributes.cs" />
2627
<Compile Include="..\src\System\Diagnostics\DsesSamplerBuilder.cs" Link="DsesSamplerBuilder.cs" />
2728
<Compile Include="..\src\System\Diagnostics\RateLimiter.cs" Link="RateLimiter.cs" />
2829
<Compile Include="..\src\System\Diagnostics\Helpers.cs" Link="Helpers.cs" />

0 commit comments

Comments
 (0)