-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Background and Motivation
I'm working on implementing the new System.Diagnostics.ActivitySource API using the OpenTelemetry-dotnet beta that was just released on top of it. I've run into a couple of pain points that I think an API tweak or two would help alleviate.
I'm consuming messages off a queue. These messages have W3C TraceParent and TraceState values stored as message headers. If I wanted to create an Activity using these values as a parent the API provides:
public sealed class ActivitySource
{
public Activity? StartActivity(string name, ActivityKind kind, string parentId, IEnumerable<KeyValuePair<string, string?>>? tags = null, IEnumerable<ActivityLink>? links = null, DateTimeOffset startTime = default);
}That would work fine but I don't want to create a parented Activity, I want to add this TraceContext as a link on that Activity.
ActivityLink only accepts ActivityContext in its ctor. There's actually no way I can find to parse a string TraceParent + TraceState into an ActivityContext. That functionality is available internally.
Proposed API
namespace System.Diagnostics
{
public readonly partial struct ActivityContext : IEquatable<ActivityContext>
{
+ public static bool TryParse(string w3cId, string? traceState, out ActivityContext context);
}
}What I'm looking for is a way to expose to users the internal parsing so I can turn my strings into a valid ActivityContext without a lot of additional work.
Workaround
What I'm doing right now is just implementing some of the internal logic myself...
public static ActivityContext CreateActivityContextFromW3CTraceContext(string traceParent, string? traceState = null)
{
if (string.IsNullOrEmpty(traceParent))
throw new ArgumentNullException(nameof(traceParent));
if (traceParent.Length != 55)
throw new FormatException($"TraceParent [{traceParent}] format is not supported.");
ReadOnlySpan<char> traceIdSpan = traceParent.AsSpan(3, 32);
ReadOnlySpan<char> spanIdSpan = traceParent.AsSpan(36, 16);
return new ActivityContext(
ActivityTraceId.CreateFromString(traceIdSpan),
ActivitySpanId.CreateFromString(spanIdSpan),
(ActivityTraceFlags)ConversionExtensions.HexByteFromChars(traceParent[53], traceParent[54]),
traceState);
}