public System.Diagnostics.ActivityTraceFlags TraceFlags { get { throw null; } }
public string? TraceState { get { throw null; } }
public bool IsRemote { get { throw null; } }
+ public static bool TryParse(string traceParent, string? traceState, out System.Diagnostics.ActivityContext context) { throw null; }
+ public static System.Diagnostics.ActivityContext Parse(string traceParent, string? traceState) { throw null; }
public static bool operator ==(System.Diagnostics.ActivityContext left, System.Diagnostics.ActivityContext right) { throw null; }
public static bool operator !=(System.Diagnostics.ActivityContext left, System.Diagnostics.ActivityContext right) { throw null; }
public bool Equals(System.Diagnostics.ActivityContext value) { throw null; }
<data name="KeyAlreadyExist" xml:space="preserve">
<value>"The collection already contains item with same key '{0}''"</value>
</data>
+ <data name="InvalidTraceParent" xml:space="preserve">
+ <value>"Invalid trace parent."</value>
+ </data>
</root>
\ No newline at end of file
#if ALLOW_PARTIALLY_TRUSTED_CALLERS
[System.Security.SecuritySafeCriticalAttribute]
#endif
- internal static bool TryConvertIdToContext(string id, out ActivityContext context)
+ internal static bool TryConvertIdToContext(string traceParent, string? traceState, out ActivityContext context)
{
context = default;
- if (!IsW3CId(id))
+ if (!IsW3CId(traceParent))
{
return false;
}
- ReadOnlySpan<char> traceIdSpan = id.AsSpan(3, 32);
- ReadOnlySpan<char> spanIdSpan = id.AsSpan(36, 16);
+ ReadOnlySpan<char> traceIdSpan = traceParent.AsSpan(3, 32);
+ ReadOnlySpan<char> spanIdSpan = traceParent.AsSpan(36, 16);
if (!ActivityTraceId.IsLowerCaseHexAndNotAllZeros(traceIdSpan) || !ActivityTraceId.IsLowerCaseHexAndNotAllZeros(spanIdSpan) ||
- !HexConverter.IsHexLowerChar(id[53]) || !HexConverter.IsHexLowerChar(id[54]))
+ !HexConverter.IsHexLowerChar(traceParent[53]) || !HexConverter.IsHexLowerChar(traceParent[54]))
{
return false;
}
- context = new ActivityContext(new ActivityTraceId(traceIdSpan.ToString()), new ActivitySpanId(spanIdSpan.ToString()), (ActivityTraceFlags) ActivityTraceId.HexByteFromChars(id[53], id[54]));
+ context = new ActivityContext(
+ new ActivityTraceId(traceIdSpan.ToString()),
+ new ActivitySpanId(spanIdSpan.ToString()),
+ (ActivityTraceFlags) ActivityTraceId.HexByteFromChars(traceParent[53], traceParent[54]),
+ traceState);
+
return true;
}
/// </remarks>
public bool IsRemote { get; }
+ /// <summary>
+ /// Parse W3C trace context headers to ActivityContext object.
+ /// </summary>
+ /// <param name="traceParent">W3C trace parent header.</param>
+ /// <param name="traceState">W3C trace state.</param>
+ /// <param name="context">The ActivityContext object created from the parsing operation.</param>
+ public static bool TryParse(string traceParent, string? traceState, out ActivityContext context)
+ {
+ if (traceParent == null)
+ {
+ throw new ArgumentNullException(nameof(traceParent));
+ }
+
+ return Activity.TryConvertIdToContext(traceParent, traceState, out context);
+ }
+
+ /// <summary>
+ /// Parse W3C trace context headers to ActivityContext object.
+ /// </summary>
+ /// <param name="traceParent">W3C trace parent header.</param>
+ /// <param name="traceState">Trace state.</param>
+ /// <returns>
+ /// The ActivityContext object created from the parsing operation.
+ /// </returns>
+ public static ActivityContext Parse(string traceParent, string? traceState)
+ {
+ if (!TryParse(traceParent, traceState, out ActivityContext context))
+ {
+ throw new ArgumentException(SR.InvalidTraceParent);
+ }
+
+ return context;
+ }
+
public bool Equals(ActivityContext value) => SpanId.Equals(value.SpanId) && TraceId.Equals(value.TraceId) && TraceFlags == value.TraceFlags && TraceState == value.TraceState;
public override bool Equals(object? obj) => (obj is ActivityContext context) ? Equals(context) : false;
{
if (!canUseContext.HasValue)
{
- canUseContext = Activity.TryConvertIdToContext(parentId, out ActivityContext ctx);
+ canUseContext = Activity.TryConvertIdToContext(parentId, traceState: null, out ActivityContext ctx);
if (canUseContext.Value)
{
dataWithContext = new ActivityCreationOptions<ActivityContext>(data.Source, data.Name, ctx, data.Kind, data.Tags, data.Links);
}).Dispose();
}
+ [Fact]
+ public void TestActivityContextParsing()
+ {
+ const string w3cId = "00-99d43cb30a4cdb4fbeee3a19c29201b0-e82825765f051b47-01";
+ Assert.True(ActivityContext.TryParse(w3cId, "k=v", out ActivityContext context));
+ Assert.Equal("99d43cb30a4cdb4fbeee3a19c29201b0", context.TraceId.ToHexString());
+ Assert.Equal("e82825765f051b47", context.SpanId.ToHexString());
+ Assert.Equal(ActivityTraceFlags.Recorded, context.TraceFlags);
+ Assert.Equal("k=v", context.TraceState);
+
+ context = ActivityContext.Parse(w3cId, "k=v");
+ Assert.Equal("99d43cb30a4cdb4fbeee3a19c29201b0", context.TraceId.ToHexString());
+ Assert.Equal("e82825765f051b47", context.SpanId.ToHexString());
+ Assert.Equal(ActivityTraceFlags.Recorded, context.TraceFlags);
+ Assert.Equal("k=v", context.TraceState);
+
+ context = ActivityContext.Parse(w3cId, null);
+ Assert.Null(context.TraceState);
+
+ Assert.Throws<ArgumentNullException>(() => ActivityContext.TryParse(null, "k=v", out context));
+ Assert.Throws<ArgumentNullException>(() => ActivityContext.Parse(null, null));
+ Assert.Throws<ArgumentException>(() => ActivityContext.Parse("BadW3C", null));
+
+ const string invalidW3CContext = "00-Z9d43cb30a4cdb4fbeee3a19c29201b0-e82825765f051b47-01";
+ Assert.False(ActivityContext.TryParse(invalidW3CContext, null, out context));
+ }
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void TestCreatingActivityUsingDifferentParentIds()