Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public string? Id
public System.Diagnostics.Activity? Parent { get { throw null; } }
public string? ParentId { get { throw null; } }
public System.Diagnostics.ActivitySpanId ParentSpanId { get { throw null; } }
public bool RandomizedTraceId { get { throw null; } }
public bool Recorded { get { throw null; } }
public string? RootId { get { throw null; } }
public System.Diagnostics.ActivitySpanId SpanId { get { throw null; } }
Expand Down Expand Up @@ -184,6 +185,7 @@ public enum ActivityTraceFlags
{
None = 0,
Recorded = 1,
RandomTraceId = 2,
}
public readonly partial struct ActivityTraceId : System.IEquatable<System.Diagnostics.ActivityTraceId>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,11 @@ public ActivityTraceId TraceId
}
}

/// <summary>
/// True if the W3CIdFlags.RandomTraceId flag is set.
/// </summary>
public bool RandomizedTraceId { get => (ActivityTraceFlags & ActivityTraceFlags.RandomTraceId) != 0; }

/// <summary>
/// True if the W3CIdFlags.Recorded flag is set.
/// </summary>
Expand Down Expand Up @@ -1289,7 +1294,20 @@ private void GenerateW3CId()
if (!TrySetTraceIdFromParent())
{
Func<ActivityTraceId>? traceIdGenerator = TraceIdGenerator;
ActivityTraceId id = traceIdGenerator == null ? ActivityTraceId.CreateRandom() : traceIdGenerator();
ActivityTraceId id;

if (traceIdGenerator == null)
{
id = ActivityTraceId.CreateRandom();
// Set RandomTraceId flag when using the default random generator
ActivityTraceFlags |= ActivityTraceFlags.RandomTraceId;
}
else
{
// Using custom generator
id = traceIdGenerator();
}

_traceId = id.ToHexString();
}
}
Expand Down Expand Up @@ -1872,6 +1890,7 @@ public enum ActivityTraceFlags
{
None = 0b_0_0000000,
Recorded = 0b_0_0000001, // The Activity (or more likely its parents) has been marked as useful to record
RandomTraceId = 0b_0_0000010, // The Activity has a randomized TraceId
}

/// <summary>
Expand Down
117 changes: 107 additions & 10 deletions src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1151,10 +1151,39 @@ public void ActivityTraceFlagsTests()
Assert.Equal($"00-0123456789abcdef0123456789abcdef-{activity.SpanId.ToHexString()}-01", activity.Id);
Assert.Equal(ActivityTraceFlags.Recorded, activity.ActivityTraceFlags);
Assert.True(activity.Recorded);
Assert.False(activity.RandomizedTraceId);
activity.Stop();

// Set the 'Recorded' bit by using SetParentId by using the TraceId, SpanId, ActivityTraceFlags overload
// Set the 'RandomTraceId' bit by using SetParentId with a -02 flags.
activity = new Activity("activity2");
activity.SetParentId("00-0123456789abcdef0123456789abcdef-0123456789abcdef-02");
activity.Start();
Assert.Equal(ActivityIdFormat.W3C, activity.IdFormat);
Assert.Equal("0123456789abcdef0123456789abcdef", activity.TraceId.ToHexString());
Assert.Equal("0123456789abcdef", activity.ParentSpanId.ToHexString());
Assert.True(IdIsW3CFormat(activity.Id));
Assert.Equal($"00-0123456789abcdef0123456789abcdef-{activity.SpanId.ToHexString()}-02", activity.Id);
Assert.Equal(ActivityTraceFlags.RandomTraceId, activity.ActivityTraceFlags);
Assert.False(activity.Recorded);
Assert.True(activity.RandomizedTraceId);
activity.Stop();

// Set the 'Recorded' and 'RandomTraceId' bits by using SetParentId with a -03 flags.
activity = new Activity("activity3");
activity.SetParentId("00-0123456789abcdef0123456789abcdef-0123456789abcdef-03");
activity.Start();
Assert.Equal(ActivityIdFormat.W3C, activity.IdFormat);
Assert.Equal("0123456789abcdef0123456789abcdef", activity.TraceId.ToHexString());
Assert.Equal("0123456789abcdef", activity.ParentSpanId.ToHexString());
Assert.True(IdIsW3CFormat(activity.Id));
Assert.Equal($"00-0123456789abcdef0123456789abcdef-{activity.SpanId.ToHexString()}-03", activity.Id);
Assert.Equal(ActivityTraceFlags.Recorded | ActivityTraceFlags.RandomTraceId, activity.ActivityTraceFlags);
Assert.True(activity.Recorded);
Assert.True(activity.RandomizedTraceId);
activity.Stop();

// Set the 'Recorded' bit by using SetParentId by using the TraceId, SpanId, ActivityTraceFlags overload
activity = new Activity("activity4");
ActivityTraceId activityTraceId = ActivityTraceId.CreateRandom();
activity.SetParentId(activityTraceId, ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded);
activity.Start();
Expand All @@ -1164,11 +1193,41 @@ public void ActivityTraceFlagsTests()
Assert.Equal($"00-{activity.TraceId.ToHexString()}-{activity.SpanId.ToHexString()}-01", activity.Id);
Assert.Equal(ActivityTraceFlags.Recorded, activity.ActivityTraceFlags);
Assert.True(activity.Recorded);
Assert.False(activity.RandomizedTraceId);
activity.Stop();

// Set the 'RandomTraceId' bit by using SetParentId by using the TraceId, SpanId, ActivityTraceFlags overload
activity = new Activity("activity5");
activityTraceId = ActivityTraceId.CreateRandom();
activity.SetParentId(activityTraceId, ActivitySpanId.CreateRandom(), ActivityTraceFlags.RandomTraceId);
activity.Start();
Assert.Equal(ActivityIdFormat.W3C, activity.IdFormat);
Assert.Equal(activityTraceId.ToHexString(), activity.TraceId.ToHexString());
Assert.True(IdIsW3CFormat(activity.Id));
Assert.Equal($"00-{activity.TraceId.ToHexString()}-{activity.SpanId.ToHexString()}-02", activity.Id);
Assert.Equal(ActivityTraceFlags.RandomTraceId, activity.ActivityTraceFlags);
Assert.False(activity.Recorded);
Assert.True(activity.RandomizedTraceId);
activity.Stop();


// Set the 'Recorded' and 'RandomTraceId' bits by using SetParentId by using the TraceId, SpanId, ActivityTraceFlags overload
activity = new Activity("activity6");
activityTraceId = ActivityTraceId.CreateRandom();
activity.SetParentId(activityTraceId, ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded | ActivityTraceFlags.RandomTraceId);
activity.Start();
Assert.Equal(ActivityIdFormat.W3C, activity.IdFormat);
Assert.Equal(activityTraceId.ToHexString(), activity.TraceId.ToHexString());
Assert.True(IdIsW3CFormat(activity.Id));
Assert.Equal($"00-{activity.TraceId.ToHexString()}-{activity.SpanId.ToHexString()}-03", activity.Id);
Assert.Equal(ActivityTraceFlags.Recorded | ActivityTraceFlags.RandomTraceId, activity.ActivityTraceFlags);
Assert.True(activity.Recorded);
Assert.True(activity.RandomizedTraceId);
activity.Stop();

/****************************************************/
// Set the 'Recorded' bit explicitly after the fact.
activity = new Activity("activity3");
// Set the 'Recorded' and 'RandomTraceId' bits explicitly after the fact.
activity = new Activity("activity7");
activity.SetParentId("00-0123456789abcdef0123456789abcdef-0123456789abcdef-00");
activity.Start();
Assert.Equal(ActivityIdFormat.W3C, activity.IdFormat);
Expand All @@ -1178,37 +1237,52 @@ public void ActivityTraceFlagsTests()
Assert.Equal($"00-{activity.TraceId.ToHexString()}-{activity.SpanId.ToHexString()}-00", activity.Id);
Assert.Equal(ActivityTraceFlags.None, activity.ActivityTraceFlags);
Assert.False(activity.Recorded);
Assert.False(activity.RandomizedTraceId);

activity.ActivityTraceFlags = ActivityTraceFlags.Recorded;
Assert.Equal(ActivityTraceFlags.Recorded, activity.ActivityTraceFlags);
Assert.True(activity.Recorded);
Assert.False(activity.RandomizedTraceId);

activity.ActivityTraceFlags = ActivityTraceFlags.RandomTraceId;
Assert.Equal(ActivityTraceFlags.RandomTraceId, activity.ActivityTraceFlags);
Assert.False(activity.Recorded);
Assert.True(activity.RandomizedTraceId);

activity.ActivityTraceFlags = ActivityTraceFlags.Recorded | ActivityTraceFlags.RandomTraceId;
Assert.Equal(ActivityTraceFlags.Recorded | ActivityTraceFlags.RandomTraceId, activity.ActivityTraceFlags);
Assert.True(activity.Recorded);
Assert.True(activity.RandomizedTraceId);

activity.Stop();

/****************************************************/
// Confirm that the flags are propagated to children.
activity = new Activity("activity4");
activity.SetParentId("00-0123456789abcdef0123456789abcdef-0123456789abcdef-01");
activity = new Activity("activity8");
activity.SetParentId("00-0123456789abcdef0123456789abcdef-0123456789abcdef-03");
activity.Start();
Assert.Equal(activity, Activity.Current);
Assert.Equal(ActivityIdFormat.W3C, activity.IdFormat);
Assert.Equal("0123456789abcdef0123456789abcdef", activity.TraceId.ToHexString());
Assert.Equal("0123456789abcdef", activity.ParentSpanId.ToHexString());
Assert.True(IdIsW3CFormat(activity.Id));
Assert.Equal($"00-{activity.TraceId.ToHexString()}-{activity.SpanId.ToHexString()}-01", activity.Id);
Assert.Equal(ActivityTraceFlags.Recorded, activity.ActivityTraceFlags);
Assert.Equal($"00-{activity.TraceId.ToHexString()}-{activity.SpanId.ToHexString()}-03", activity.Id);
Assert.Equal(ActivityTraceFlags.Recorded | ActivityTraceFlags.RandomTraceId, activity.ActivityTraceFlags);
Assert.True(activity.Recorded);
Assert.True(activity.RandomizedTraceId);

// create a child
var childActivity = new Activity("activity4Child");
var childActivity = new Activity("activity8Child");
childActivity.Start();
Assert.Equal(childActivity, Activity.Current);

Assert.Equal("0123456789abcdef0123456789abcdef", childActivity.TraceId.ToHexString());
Assert.NotEqual(activity.SpanId.ToHexString(), childActivity.SpanId.ToHexString());
Assert.True(IdIsW3CFormat(childActivity.Id));
Assert.Equal($"00-{childActivity.TraceId.ToHexString()}-{childActivity.SpanId.ToHexString()}-01", childActivity.Id);
Assert.Equal(ActivityTraceFlags.Recorded, childActivity.ActivityTraceFlags);
Assert.Equal($"00-{childActivity.TraceId.ToHexString()}-{childActivity.SpanId.ToHexString()}-03", childActivity.Id);
Assert.Equal(ActivityTraceFlags.Recorded | ActivityTraceFlags.RandomTraceId, childActivity.ActivityTraceFlags);
Assert.True(childActivity.Recorded);
Assert.True(childActivity.RandomizedTraceId);

childActivity.Stop();
activity.Stop();
Expand Down Expand Up @@ -2190,12 +2264,35 @@ public void TraceIdCustomGenerationTest()
a.Start();

Assert.Equal(ActivityTraceId.CreateFromBytes(traceIdBytes), a.TraceId);
Assert.False(a.RandomizedTraceId);

a.Stop();
}
}).Dispose();
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void TraceIdDefaultGenerationSetsRandomFlag()
{
RemoteExecutor.Invoke(() =>
{
Activity.DefaultIdFormat = ActivityIdFormat.W3C;
Activity.TraceIdGenerator = null; // Ensure we're using the default generator

Activity a = new Activity("DefaultRandomTraceId");
a.Start();

// Default random generator should set RandomTraceId flag
Assert.True(a.RandomizedTraceId);
Assert.Equal(ActivityTraceFlags.RandomTraceId, a.ActivityTraceFlags & ActivityTraceFlags.RandomTraceId);

// Verify TraceId is not all zeros
Assert.NotEqual("00000000000000000000000000000000", a.TraceId.ToHexString());

a.Stop();
}).Dispose();
}

[Fact]
public void EnumerateTagObjectsTest()
{
Expand Down
Loading