From 7c5d554822d96686dfc1a6191ca31a6276a1800e Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Sun, 20 Jun 2021 13:10:10 -0700 Subject: [PATCH 1/6] Propagators Support --- ...em.Diagnostics.DiagnosticSourceActivity.cs | 20 +- ...System.Diagnostics.DiagnosticSource.csproj | 1 + .../System/Diagnostics/TextMapPropagator.cs | 520 ++++++++++++++++++ 3 files changed, 540 insertions(+), 1 deletion(-) create mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index 482a58bb414ea..0a8b950e341d5 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -253,7 +253,25 @@ public sealed class ActivityListener : IDisposable public System.Diagnostics.SampleActivity? SampleUsingParentId { get { throw null; } set { throw null; } } public System.Diagnostics.SampleActivity? Sample { get { throw null; } set { throw null; } } public void Dispose() { throw null; } - } + } + + public delegate bool PropagatorGetterCallback(object carrier, string fieldName, out string? value); + + public abstract class TextMapPropagator + { + public abstract System.Collections.Generic.IEnumerable Fields { get; } + public abstract bool Inject(System.Diagnostics.Activity activity, object carrier, Action setter); + public abstract bool Inject(System.Diagnostics.ActivityContext context, object carrier, Action setter); + public abstract bool Inject(System.Collections.Generic.IEnumerable> baggage, object carrier, Action setter); + public abstract bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value); + public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out System.Diagnostics.ActivityContext context); + public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out System.Collections.Generic.IEnumerable>? baggage); + public static TextMapPropagator DefaultPropagator { get; set; } + public static TextMapPropagator CreateLegacyPropagator() { throw null; } + public static TextMapPropagator CreatePassThroughPropagator() { throw null; } + public static TextMapPropagator CreateOutputSuppressionPropagator() { throw null; } + public static TextMapPropagator CreateW3CPropagator() { throw null; } + } } namespace System.Diagnostics.Metrics diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index 6c8fbb0203c4a..1d9c44bcdc927 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -51,6 +51,7 @@ + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs new file mode 100644 index 0000000000000..ff1a41494e819 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs @@ -0,0 +1,520 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text; +using System.Net; +using System.Collections.Generic; + +namespace System.Diagnostics +{ + public delegate bool PropagatorGetterCallback(object carrier, string fieldName, out string? value); + + public abstract class TextMapPropagator + { + public abstract IEnumerable Fields { get; } + + // Inject + + public abstract bool Inject(Activity activity, object carrier, Action setter); + public abstract bool Inject(ActivityContext context, object carrier, Action setter); + public abstract bool Inject(IEnumerable> baggage, object carrier, Action setter); + + // Extract + + public abstract bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value); + public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out ActivityContext context); + public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out IEnumerable>? baggage); + + // + // Static APIs + // + + public static TextMapPropagator DefaultPropagator { get; set; } = CreateLegacyPropagator(); + + // For Microsoft compatibility. e.g., it will propagate Baggage header name as "Correlation-Context" instead of "baggage". + public static TextMapPropagator CreateLegacyPropagator() => new LegacyTextMapPropagator(); + + // Suppress context propagation. + public static TextMapPropagator CreateOutputSuppressionPropagator() => new OutputSuppressionPropagator(); + + // propagate only root parent context and ignore any intermediate created context. + public static TextMapPropagator CreatePassThroughPropagator() => new PassThroughPropagator(); + + // Conform to the W3C specs https://www.w3.org/TR/trace-context/ & https://www.w3.org/TR/2020/WD-baggage-20201020/ + public static TextMapPropagator CreateW3CPropagator() => new W3CPropagator(); + + // + // Internal + // + + internal const string TraceParent = "traceparent"; + internal const string RequestId = "Request-Id"; + internal const string TraceState = "tracestate"; + internal const string Baggage = "baggage"; + internal const string CorrelationContext = "Correlation-Context"; + internal static readonly char[] EqualSignSeparator = new[] { '=' }; + internal static readonly char[] CommaSignSeparator = new[] { ',' }; + internal const int MaxBaggageLength = 8192; + internal const int MaxBaggageItems = 180; + + internal static void InjectBaggage(object carrier, IEnumerable> baggage, Action setter, bool injectAsW3C = false) + { + using (IEnumerator> e = baggage.GetEnumerator()) + { + if (e.MoveNext()) + { + StringBuilder baggageList = new StringBuilder(); + do + { + KeyValuePair item = e.Current; + baggageList.Append(WebUtility.UrlEncode(item.Key)).Append('=').Append(WebUtility.UrlEncode(item.Value)).Append(','); + } + while (e.MoveNext()); + baggageList.Remove(baggageList.Length - 1, 1); + setter(carrier, injectAsW3C ? Baggage : CorrelationContext, baggageList.ToString()); + } + } + } + + internal static bool TryExtractBaggage(string baggagestring, out IEnumerable>? baggage) + { + baggage = null; + int baggageLength = -1; + List>? baggageList = null; + + if (string.IsNullOrEmpty(baggagestring)) + { + return true; + } + + foreach (string pair in baggagestring.Split(CommaSignSeparator)) + { + baggageLength += pair.Length + 1; // pair and comma + + if (baggageLength >= MaxBaggageLength || baggageList?.Count >= MaxBaggageItems) + { + break; + } + + if (pair.IndexOf('=') < 0) + { + continue; + } + + var parts = pair.Split(EqualSignSeparator, 2); + if (parts.Length != 2) + { + continue; + } + + var key = WebUtility.UrlDecode(parts[0]); + var value = WebUtility.UrlDecode(parts[1]); + + if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value)) + { + continue; + } + + if (baggageList is null) + { + baggageList = new(); + } + + baggageList.Add(new KeyValuePair(key, value)); + } + + baggage = baggageList; + return baggageList != null; + } + + internal static bool InjectContext(ActivityContext context, object carrier, Action setter) + { + if (context == default || setter is null || context.TraceId == default || context.SpanId == default) + { + return false; + } + + Span traceParent = stackalloc char[55]; + traceParent[0] = '0'; + traceParent[1] = '0'; + traceParent[2] = '-'; + traceParent[35] = '-'; + traceParent[52] = '-'; + CopyStringToSpan(context.TraceId.ToHexString(), traceParent.Slice(3, 32)); + CopyStringToSpan(context.SpanId.ToHexString(), traceParent.Slice(36, 16)); + HexConverter.ToCharsBuffer((byte)(context.TraceFlags & ActivityTraceFlags.Recorded), traceParent.Slice(53, 2), 0, HexConverter.Casing.Lower); + + setter(carrier, TraceParent, traceParent.ToString()); + + string? tracestateStr = context.TraceState; + if (tracestateStr?.Length > 0) + { + setter(carrier, TraceState, tracestateStr); + } + + return true; + } + + internal static bool LegacyExtract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value) + { + value = null; + + if (fieldName is null || getter is null) + { + return false; + } + + if (fieldName == TraceParent || fieldName == RequestId || fieldName == TraceState) + { + // We expect one value here so we don't bother check more values. + getter(carrier, fieldName, out value); + return true; + } + + return false; + } + + internal static bool LegacyExtract(object carrier, PropagatorGetterCallback getter, out ActivityContext context) + { + context = default; + + if (getter is null) + { + return false; + } + + getter(carrier, TraceParent, out string? traceParent); + getter(carrier, TraceState, out string? traceState); + + return ActivityContext.TryParse(traceParent, traceState, out context); + } + + internal static bool LegacyExtract(object carrier, PropagatorGetterCallback getter, out IEnumerable>? baggage) + { + baggage = null; + if (getter is null) + { + return false; + } + + getter(carrier, Baggage, out string? theBaggage); + if (theBaggage is null || !TryExtractBaggage(theBaggage, out baggage)) + { + getter(carrier, CorrelationContext, out theBaggage); + if (theBaggage is not null) + { + TryExtractBaggage(theBaggage, out baggage); + } + } + + return true; + } + + internal static void CopyStringToSpan(string s, Span span) + { + Debug.Assert(s is not null); + Debug.Assert(s.Length == span.Length); + + for (int i = 0; i < s.Length; i++) + { + span[i] = s[i]; + } + } + + } + + internal class LegacyTextMapPropagator : TextMapPropagator + { + // + // Fields + // + + public override IEnumerable Fields { get; } = new HashSet() { TraceParent, RequestId, TraceState, Baggage, CorrelationContext }; + + // + // Inject + // + + public override bool Inject(Activity activity, object carrier, Action setter) + { + if (activity is null || setter == default) + { + return false; + } + + string? id = activity.Id; + if (id is null) + { + return false; + } + + if (activity.IdFormat == ActivityIdFormat.W3C) + { + setter(carrier, TraceParent, id); + if (activity.TraceStateString is not null) + { + setter(carrier, TraceState, activity.TraceStateString); + } + } + else + { + setter(carrier, RequestId, id); + } + + InjectBaggage(carrier, activity.Baggage, setter); + + return true; + } + + public override bool Inject(ActivityContext context, object carrier, Action setter) => + InjectContext(context, carrier, setter); + + public override bool Inject(IEnumerable> baggage, object carrier, Action setter) + { + if (setter is null) + { + return false; + } + + if (baggage is null) + { + return true; // nothing need to be done + } + + InjectBaggage(carrier, baggage, setter); + return true; + } + + // + // Extract + // + + public override bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value) => + LegacyExtract(carrier, fieldName, getter, out value); + + public override bool Extract(object carrier, PropagatorGetterCallback getter, out ActivityContext context) => + LegacyExtract(carrier, getter, out context); + + public override bool Extract(object carrier, PropagatorGetterCallback getter, out IEnumerable>? baggage) => + LegacyExtract(carrier, getter, out baggage); + } + + internal class PassThroughPropagator : TextMapPropagator + { + // + // Fields + // + public override IEnumerable Fields { get; } = new HashSet() { TraceParent, RequestId, TraceState, Baggage, CorrelationContext }; + + // Inject + + public override bool Inject(Activity activity, object carrier, Action setter) + { + GetRootId(out string? parentId, out string? traceState, out bool isW3c); + if (parentId is null) + { + return true; + } + + setter(carrier, isW3c ? TraceParent : RequestId, parentId); + + if (traceState is not null) + { + setter(carrier, TraceState, traceState); + } + + return true; + } + + public override bool Inject(ActivityContext context, object carrier, Action setter) => + Inject((Activity) null!, carrier, setter); + + public override bool Inject(IEnumerable> baggage, object carrier, Action setter) + { + IEnumerable>? parentBaggage = GetRootBaggage(); + + if (parentBaggage is not null) + { + InjectBaggage(carrier, parentBaggage, setter); + } + + return true; + } + + // + // Extract + // + + public override bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value) => + LegacyExtract(carrier, fieldName, getter, out value); + + public override bool Extract(object carrier, PropagatorGetterCallback getter, out ActivityContext context) => + LegacyExtract(carrier, getter, out context); + + public override bool Extract(object carrier, PropagatorGetterCallback getter, out IEnumerable>? baggage) => + LegacyExtract(carrier, getter, out baggage); + + private static void GetRootId(out string? parentId, out string? traceState, out bool isW3c) + { + Activity? activity = Activity.Current; + if (activity is null) + { + parentId = null; + traceState = null; + isW3c = false; + return; + } + + while (activity is not null && activity.Parent is not null) + { + activity = activity.Parent; + } + + traceState = activity?.TraceStateString; + parentId = activity?.ParentId ?? activity?.Id; + isW3c = activity?.IdFormat == ActivityIdFormat.W3C; + } + + private static IEnumerable>? GetRootBaggage() + { + Activity? activity = Activity.Current; + if (activity is null) + { + return null; + } + + while (activity is not null && activity.Parent is not null) + { + activity = activity.Parent; + } + + return activity?.Baggage; + } + } + + internal class OutputSuppressionPropagator : TextMapPropagator + { + // + // Fields + // + public override IEnumerable Fields { get; } = new HashSet() { TraceParent, RequestId, TraceState, Baggage, CorrelationContext }; + + // Inject + + public override bool Inject(Activity activity, object carrier, Action setter) => true; + public override bool Inject(ActivityContext context, object carrier, Action setter) => true; + public override bool Inject(IEnumerable> baggage, object carrier, Action setter) => true; + + // Extract + + public override bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value) => + LegacyExtract(carrier, fieldName, getter, out value); + + public override bool Extract(object carrier, PropagatorGetterCallback getter, out ActivityContext context) => + LegacyExtract(carrier, getter, out context); + + public override bool Extract(object carrier, PropagatorGetterCallback getter, out IEnumerable>? baggage) => + LegacyExtract(carrier, getter, out baggage); + } + + internal class W3CPropagator : TextMapPropagator + { + // + // Fields + // + + public override IEnumerable Fields { get; } = new HashSet() { TraceParent, TraceState, Baggage }; + + // + // Inject + // + + public override bool Inject(Activity activity, object carrier, Action setter) + { + if (activity is null || setter == default || activity.IdFormat != ActivityIdFormat.W3C) + { + return false; + } + + string? id = activity.Id; + if (id is null) + { + return false; + } + + setter(carrier, TraceParent, id); + if (activity.TraceStateString is not null) + { + setter(carrier, TraceState, activity.TraceStateString); + } + + InjectBaggage(carrier, activity.Baggage, setter, injectAsW3C: true); + + return true; + } + + public override bool Inject(ActivityContext context, object carrier, Action setter) => + InjectContext(context, carrier, setter); + + public override bool Inject(IEnumerable> baggage, object carrier, Action setter) + { + if (setter is null) + { + return false; + } + + if (baggage is null) + { + return true; // nothing need to be done + } + + InjectBaggage(carrier, baggage, setter, true); + return true; + } + + // + // Extract + // + + public override bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value) + { + value = null; + + if (fieldName is null || getter is null || (fieldName != TraceParent && fieldName != TraceState)) + { + return false; + } + + // We expect one value here so we don't bother check more values. + getter(carrier, fieldName, out value); + + if (fieldName == TraceParent && !ActivityContext.TryParse(value, null, out ActivityContext context)) + { + return false; + } + + return true; + } + + public override bool Extract(object carrier, PropagatorGetterCallback getter, out ActivityContext context) => + LegacyExtract(carrier, getter, out context); + + public override bool Extract(object carrier, PropagatorGetterCallback getter, out IEnumerable>? baggage) + { + baggage = null; + if (getter is null) + { + return false; + } + + getter(carrier, Baggage, out string? theBaggage); + + if (theBaggage is not null) + { + return TryExtractBaggage(theBaggage, out baggage); + } + + return true; + } + } +} \ No newline at end of file From cf7537610b099b2c64da2741f42053687ca1fd06 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Mon, 21 Jun 2021 10:52:13 -0700 Subject: [PATCH 2/6] Address Feedback --- .../System.Diagnostics.DiagnosticSourceActivity.cs | 4 ++-- .../src/System/Diagnostics/TextMapPropagator.cs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index 0a8b950e341d5..6e595a7949214 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -255,11 +255,11 @@ public sealed class ActivityListener : IDisposable public void Dispose() { throw null; } } - public delegate bool PropagatorGetterCallback(object carrier, string fieldName, out string? value); public abstract class TextMapPropagator { - public abstract System.Collections.Generic.IEnumerable Fields { get; } + public delegate bool PropagatorGetterCallback(object carrier, string fieldName, out string? value); + public abstract System.Collections.Generic.IReadOnlyCollection Fields { get; } public abstract bool Inject(System.Diagnostics.Activity activity, object carrier, Action setter); public abstract bool Inject(System.Diagnostics.ActivityContext context, object carrier, Action setter); public abstract bool Inject(System.Collections.Generic.IEnumerable> baggage, object carrier, Action setter); diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs index ff1a41494e819..ca6a701e69ff0 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs @@ -7,11 +7,11 @@ namespace System.Diagnostics { - public delegate bool PropagatorGetterCallback(object carrier, string fieldName, out string? value); - public abstract class TextMapPropagator { - public abstract IEnumerable Fields { get; } + public delegate bool PropagatorGetterCallback(object carrier, string fieldName, out string? value); + + public abstract IReadOnlyCollection Fields { get; } // Inject @@ -229,7 +229,7 @@ internal class LegacyTextMapPropagator : TextMapPropagator // Fields // - public override IEnumerable Fields { get; } = new HashSet() { TraceParent, RequestId, TraceState, Baggage, CorrelationContext }; + public override IReadOnlyCollection Fields { get; } = new HashSet() { TraceParent, RequestId, TraceState, Baggage, CorrelationContext }; // // Inject @@ -304,7 +304,7 @@ internal class PassThroughPropagator : TextMapPropagator // // Fields // - public override IEnumerable Fields { get; } = new HashSet() { TraceParent, RequestId, TraceState, Baggage, CorrelationContext }; + public override IReadOnlyCollection Fields { get; } = new HashSet() { TraceParent, RequestId, TraceState, Baggage, CorrelationContext }; // Inject @@ -397,7 +397,7 @@ internal class OutputSuppressionPropagator : TextMapPropagator // // Fields // - public override IEnumerable Fields { get; } = new HashSet() { TraceParent, RequestId, TraceState, Baggage, CorrelationContext }; + public override IReadOnlyCollection Fields { get; } = new HashSet() { TraceParent, RequestId, TraceState, Baggage, CorrelationContext }; // Inject @@ -423,7 +423,7 @@ internal class W3CPropagator : TextMapPropagator // Fields // - public override IEnumerable Fields { get; } = new HashSet() { TraceParent, TraceState, Baggage }; + public override IReadOnlyCollection Fields { get; } = new HashSet() { TraceParent, TraceState, Baggage }; // // Inject From f3b285ab02c87085c5a7fa3f82cb44a361baaa71 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Mon, 21 Jun 2021 16:58:47 -0700 Subject: [PATCH 3/6] Update Extract method. --- ...em.Diagnostics.DiagnosticSourceActivity.cs | 2 +- .../System/Diagnostics/TextMapPropagator.cs | 46 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index 6e595a7949214..5beeea85a45f2 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -263,7 +263,7 @@ public abstract class TextMapPropagator public abstract bool Inject(System.Diagnostics.Activity activity, object carrier, Action setter); public abstract bool Inject(System.Diagnostics.ActivityContext context, object carrier, Action setter); public abstract bool Inject(System.Collections.Generic.IEnumerable> baggage, object carrier, Action setter); - public abstract bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value); + public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out string? id, out string? state); public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out System.Diagnostics.ActivityContext context); public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out System.Collections.Generic.IEnumerable>? baggage); public static TextMapPropagator DefaultPropagator { get; set; } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs index ca6a701e69ff0..e107732ba6a0c 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs @@ -21,7 +21,7 @@ public abstract class TextMapPropagator // Extract - public abstract bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value); + public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out string? id, out string? state); public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out ActivityContext context); public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out IEnumerable>? baggage); @@ -155,23 +155,23 @@ internal static bool InjectContext(ActivityContext context, object carrier, Acti return true; } - internal static bool LegacyExtract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value) + internal static bool LegacyExtract(object carrier, PropagatorGetterCallback getter, out string? id, out string? state) { - value = null; - - if (fieldName is null || getter is null) + if (getter is null) { + id = null; + state = null; return false; } - if (fieldName == TraceParent || fieldName == RequestId || fieldName == TraceState) + getter(carrier, TraceParent, out id); + if (id is null) { - // We expect one value here so we don't bother check more values. - getter(carrier, fieldName, out value); - return true; + getter(carrier, RequestId, out id); } - return false; + getter(carrier, TraceState, out state); + return true; } internal static bool LegacyExtract(object carrier, PropagatorGetterCallback getter, out ActivityContext context) @@ -289,8 +289,8 @@ public override bool Inject(IEnumerable> baggage, // Extract // - public override bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value) => - LegacyExtract(carrier, fieldName, getter, out value); + public override bool Extract(object carrier, PropagatorGetterCallback getter, out string? id, out string? state) => + LegacyExtract(carrier, getter, out id, out state); public override bool Extract(object carrier, PropagatorGetterCallback getter, out ActivityContext context) => LegacyExtract(carrier, getter, out context); @@ -345,8 +345,8 @@ public override bool Inject(IEnumerable> baggage, // Extract // - public override bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value) => - LegacyExtract(carrier, fieldName, getter, out value); + public override bool Extract(object carrier, PropagatorGetterCallback getter, out string? id, out string? state) => + LegacyExtract(carrier, getter, out id, out state); public override bool Extract(object carrier, PropagatorGetterCallback getter, out ActivityContext context) => LegacyExtract(carrier, getter, out context); @@ -407,8 +407,8 @@ internal class OutputSuppressionPropagator : TextMapPropagator // Extract - public override bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value) => - LegacyExtract(carrier, fieldName, getter, out value); + public override bool Extract(object carrier, PropagatorGetterCallback getter, out string? id, out string? state) => + LegacyExtract(carrier, getter, out id, out state); public override bool Extract(object carrier, PropagatorGetterCallback getter, out ActivityContext context) => LegacyExtract(carrier, getter, out context); @@ -476,19 +476,19 @@ public override bool Inject(IEnumerable> baggage, // Extract // - public override bool Extract(object carrier, string fieldName, PropagatorGetterCallback getter, out string? value) + public override bool Extract(object carrier, PropagatorGetterCallback getter, out string? id, out string? state) { - value = null; - - if (fieldName is null || getter is null || (fieldName != TraceParent && fieldName != TraceState)) + if (getter is null) { + id = null; + state = null; return false; } - // We expect one value here so we don't bother check more values. - getter(carrier, fieldName, out value); + getter(carrier, TraceParent, out id); + getter(carrier, TraceState, out state); - if (fieldName == TraceParent && !ActivityContext.TryParse(value, null, out ActivityContext context)) + if (id is not null && !ActivityContext.TryParse(id, state, out ActivityContext context)) { return false; } From 7f4ebc5c06895254bc3e56f3c95c1ef39f85a52d Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 22 Jun 2021 19:47:04 -0700 Subject: [PATCH 4/6] Fix space trimming and baggage order --- ...em.Diagnostics.DiagnosticSourceActivity.cs | 2 +- .../System/Diagnostics/TextMapPropagator.cs | 104 +++++++++++++----- 2 files changed, 75 insertions(+), 31 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index 5beeea85a45f2..dfd7499a939db 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -266,7 +266,7 @@ public abstract class TextMapPropagator public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out string? id, out string? state); public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out System.Diagnostics.ActivityContext context); public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out System.Collections.Generic.IEnumerable>? baggage); - public static TextMapPropagator DefaultPropagator { get; set; } + public static TextMapPropagator Default { get; set; } public static TextMapPropagator CreateLegacyPropagator() { throw null; } public static TextMapPropagator CreatePassThroughPropagator() { throw null; } public static TextMapPropagator CreateOutputSuppressionPropagator() { throw null; } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs index e107732ba6a0c..8a4743b05a909 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs @@ -29,7 +29,7 @@ public abstract class TextMapPropagator // Static APIs // - public static TextMapPropagator DefaultPropagator { get; set; } = CreateLegacyPropagator(); + public static TextMapPropagator Default { get; set; } = CreateLegacyPropagator(); // For Microsoft compatibility. e.g., it will propagate Baggage header name as "Correlation-Context" instead of "baggage". public static TextMapPropagator CreateLegacyPropagator() => new LegacyTextMapPropagator(); @@ -47,15 +47,22 @@ public abstract class TextMapPropagator // Internal // + internal const char Space = ' '; + internal const char Tab = (char)9; + internal const char Comma = ','; + internal const char Semicolon = ';'; + + internal const int MaxBaggageLength = 8192; + internal const int MaxKeyValueLength = 4096; + internal const int MaxBaggageItems = 180; + internal const string TraceParent = "traceparent"; internal const string RequestId = "Request-Id"; internal const string TraceState = "tracestate"; internal const string Baggage = "baggage"; internal const string CorrelationContext = "Correlation-Context"; - internal static readonly char[] EqualSignSeparator = new[] { '=' }; - internal static readonly char[] CommaSignSeparator = new[] { ',' }; - internal const int MaxBaggageLength = 8192; - internal const int MaxBaggageItems = 180; + + internal static readonly char [] s_trimmingSpaceCharacters = new char[] { Space, Tab }; internal static void InjectBaggage(object carrier, IEnumerable> baggage, Action setter, bool injectAsW3C = false) { @@ -67,7 +74,7 @@ internal static void InjectBaggage(object carrier, IEnumerable item = e.Current; - baggageList.Append(WebUtility.UrlEncode(item.Key)).Append('=').Append(WebUtility.UrlEncode(item.Value)).Append(','); + baggageList.Append(WebUtility.UrlEncode(item.Key)).Append('=').Append(WebUtility.UrlEncode(item.Value)).Append(Comma); } while (e.MoveNext()); baggageList.Remove(baggageList.Length - 1, 1); @@ -87,41 +94,79 @@ internal static bool TryExtractBaggage(string baggagestring, out IEnumerable= MaxBaggageLength || baggageList?.Count >= MaxBaggageItems) - { - break; - } + if (currentIndex >= baggagestring.Length) { break; } // No Key exist - if (pair.IndexOf('=') < 0) - { - continue; - } + int keyStart = currentIndex; - var parts = pair.Split(EqualSignSeparator, 2); - if (parts.Length != 2) - { - continue; - } + // Search end of the key + while (currentIndex < baggagestring.Length && baggagestring[currentIndex] != Space && baggagestring[currentIndex] != Tab && baggagestring[currentIndex] != '=') { currentIndex++; } - var key = WebUtility.UrlDecode(parts[0]); - var value = WebUtility.UrlDecode(parts[1]); + if (currentIndex >= baggagestring.Length) { break; } - if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value)) + int keyEnd = currentIndex; + + if (baggagestring[currentIndex] != '=') { - continue; + // Skip Spaces + while (currentIndex < baggagestring.Length && (baggagestring[currentIndex] == Space || baggagestring[currentIndex] == Tab)) { currentIndex++; } + + if (currentIndex >= baggagestring.Length) { break; } // Wrong key format } - if (baggageList is null) + if (baggagestring[currentIndex] != '=') { break; } // wrong key format. + + currentIndex++; + + // Skip spaces + while (currentIndex < baggagestring.Length && (baggagestring[currentIndex] == Space || baggagestring[currentIndex] == Tab)) { currentIndex++; } + + if (currentIndex >= baggagestring.Length) { break; } // Wrong value format + + int valueStart = currentIndex; + + // Search end of the value + while (currentIndex < baggagestring.Length && baggagestring[currentIndex] != Space && baggagestring[currentIndex] != Tab && + baggagestring[currentIndex] != Comma && baggagestring[currentIndex] != Semicolon) + { currentIndex++; } + + if (keyStart < keyEnd && valueStart < currentIndex) { - baggageList = new(); + int keyValueLength = (keyEnd - keyStart) + (currentIndex - valueStart); + if (keyValueLength > MaxKeyValueLength || keyValueLength + baggageLength >= MaxBaggageLength) + { + break; + } + + if (baggageList is null) + { + baggageList = new(); + } + + baggageLength += keyValueLength; + + // Insert in reverse order for asp.net compatability. + baggageList.Insert(0, new KeyValuePair( + WebUtility.UrlDecode(baggagestring.Substring(keyStart, keyEnd - keyStart)).Trim(s_trimmingSpaceCharacters), + WebUtility.UrlDecode(baggagestring.Substring(valueStart, currentIndex - valueStart)).Trim(s_trimmingSpaceCharacters))); + + if (baggageList.Count >= MaxBaggageItems) + { + break; + } } - baggageList.Add(new KeyValuePair(key, value)); - } + // Skip to end of values + while (currentIndex < baggagestring.Length && baggagestring[currentIndex] != Comma) { currentIndex++; } + + currentIndex++; // Move to next key-value entry + } while (currentIndex < baggagestring.Length); baggage = baggageList; return baggageList != null; @@ -220,7 +265,6 @@ internal static void CopyStringToSpan(string s, Span span) span[i] = s[i]; } } - } internal class LegacyTextMapPropagator : TextMapPropagator From fa7d0d96e8e9d5e40029a41029668315a7d827f9 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Wed, 23 Jun 2021 10:08:36 -0700 Subject: [PATCH 5/6] Tests --- .../tests/PropagatorTests.cs | 433 ++++++++++++++++++ ....Diagnostics.DiagnosticSource.Tests.csproj | 1 + 2 files changed, 434 insertions(+) create mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/tests/PropagatorTests.cs diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/PropagatorTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/PropagatorTests.cs new file mode 100644 index 0000000000000..82d18346e979f --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/PropagatorTests.cs @@ -0,0 +1,433 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Net; +using System.Collections.Generic; +using Xunit; + +namespace System.Diagnostics.Tests +{ + public class PropagatorTests + { + private string ToString(ActivityContext context) + { + Span traceParent = stackalloc char[55]; + traceParent[0] = '0'; + traceParent[1] = '0'; + traceParent[2] = '-'; + traceParent[35] = '-'; + traceParent[52] = '-'; + CopyStringToSpan(context.TraceId.ToHexString(), traceParent.Slice(3, 32)); + CopyStringToSpan(context.SpanId.ToHexString(), traceParent.Slice(36, 16)); + traceParent[53] = '0'; + traceParent[54] = (context.TraceFlags & ActivityTraceFlags.Recorded) != 0 ? '1' : '0'; + return traceParent.ToString(); + } + + private string GetFormattedBaggage(Activity a) + { + string formattedBaggage = ""; + IEnumerator> enumerator = a.Baggage.GetEnumerator(); + while (enumerator.MoveNext()) + { + formattedBaggage += (formattedBaggage.Length > 0 ? "," : "") + enumerator.Current.Key + "=" + enumerator.Current.Value; + } + + return formattedBaggage; + } + + private static void CopyStringToSpan(string s, Span span) + { + Debug.Assert(s is not null); + Debug.Assert(s.Length == span.Length); + + for (int i = 0; i < s.Length; i++) + { + span[i] = s[i]; + } + } + + [Fact] + public void DifferentTests() + { + TextMapPropagator propagator = TextMapPropagator.Default; + + Assert.NotNull(propagator); + + Activity a = new Activity("SomeActivity"); + a.SetIdFormat(ActivityIdFormat.Hierarchical); + a.SetBaggage("B1", "v1"); + a.TraceStateString = "traceState"; + a.SetParentId("Hierarchical"); + a.Start(); + + propagator.Inject(a, null, (object carrier, string fieldName, string value) => + { + Assert.Null(carrier); + if (fieldName == "traceparent" || fieldName == "Request-Id") + { + Assert.Equal(a.Id, value); + } + else if (fieldName == "tracestate") + { + Assert.Equal(a.TraceStateString, value); + } + else if (fieldName == "Correlation-Context") + { + + string formattedBaggage = GetFormattedBaggage(a); + Assert.Equal(formattedBaggage, value); + } + else + { + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + }); + + propagator.Extract(null, (object carrier, string fieldName, out string? value) => + { + Assert.Null(carrier); + if (fieldName == "traceparent") + { + value = null; + } + else if (fieldName == "Request-Id") + { + value = a.Id; + } + else if (fieldName == "tracestate") + { + value = a.TraceStateString; + } + else + { + value = null; + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + + return true; + }, + out string? id, out string? state); + + Assert.Equal(a.Id, id); + Assert.Equal(a.TraceStateString, state); + + propagator.Extract(null, (object carrier, string fieldName, out string? value) => + { + Assert.Null(carrier); + if (fieldName == "baggage" || fieldName == "Correlation-Context") + { + value = GetFormattedBaggage(a); + } + else + { + value = null; + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + return true; + } , out IEnumerable>? baggage); + + List> list = new List>(baggage); + Assert.Equal(1, list.Count); + Assert.Equal(new KeyValuePair("B1", "v1"), list[0]); + + propagator.Extract(null, (object carrier, string fieldName, out string? value) => + { + Assert.Null(carrier); + if (fieldName == "baggage" || fieldName == "Correlation-Context") + { + value = $"{WebUtility.UrlEncode(" k1 ")} = {WebUtility.UrlEncode(" v1 ")}, {WebUtility.UrlEncode(" k2 ")} = {WebUtility.UrlEncode(" v2 ")}"; + } + else + { + value = null; + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + return true; + } , out baggage); + + list = new List>(baggage); + Assert.Equal(2, list.Count); + Assert.Equal(new KeyValuePair("k2", "v2"), list[0]); + Assert.Equal(new KeyValuePair("k1", "v1"), list[1]); + + propagator = TextMapPropagator.CreateW3CPropagator(); + propagator.Inject(a, null, (object carrier, string fieldName, string value) => + { + Assert.Null(carrier); + if (fieldName == "traceparent") + { + Assert.False(true, $"{fieldName} cannot be used with activity "); + } + else if (fieldName == "tracestate") + { + Assert.Equal(a.TraceStateString, value); + } + else if (fieldName == "baggage") + { + string formattedBaggage = GetFormattedBaggage(a); + Assert.Equal(formattedBaggage, value); + } + else + { + Assert.False(true, $"{fieldName} Unexpected Field Name Hierarchical activity Id"); + } + }); + + a = new Activity("W3CActivity"); + a.SetIdFormat(ActivityIdFormat.W3C); + a.SetBaggage("B2", "v2"); + a.TraceStateString = "W3CtraceState"; + a.Start(); + + propagator.Inject(a, null, (object carrier, string fieldName, string value) => + { + Assert.Null(carrier); + if (fieldName == "traceparent") + { + Assert.Equal(a.Id, value); + } + else if (fieldName == "tracestate") + { + Assert.Equal(a.TraceStateString, value); + } + else if (fieldName == "baggage") + { + string formattedBaggage = GetFormattedBaggage(a); + Assert.Equal(formattedBaggage, value); + } + else + { + Assert.False(true, $"{fieldName} Unexpected Field Name Hierarchical activity Id"); + } + }); + + propagator.Extract(null, (object carrier, string fieldName, out string? value) => + { + Assert.Null(carrier); + if (fieldName == "traceparent") + { + value = a.Id; + } + else if (fieldName == "tracestate") + { + value = a.TraceStateString; + } + else + { + value = null; + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + return true; + }, out id, out state); + + Assert.Equal(a.Id, id); + Assert.Equal(a.TraceStateString, state); + + propagator.Extract(null, (object carrier, string fieldName, out string? value) => + { + Assert.Null(carrier); + if (fieldName == "traceparent") + { + value = a.Id; + } + else if (fieldName == "tracestate") + { + value = a.TraceStateString; + } + else + { + value = null; + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + return true; + }, out ActivityContext context); + + Span traceParent = stackalloc char[55]; + traceParent[0] = '0'; + traceParent[1] = '0'; + traceParent[2] = '-'; + traceParent[35] = '-'; + traceParent[52] = '-'; + CopyStringToSpan(context.TraceId.ToHexString(), traceParent.Slice(3, 32)); + CopyStringToSpan(context.SpanId.ToHexString(), traceParent.Slice(36, 16)); + traceParent[53] = '0'; + traceParent[54] = a.Recorded ? '1' : '0'; + + Assert.Equal(a.Id, traceParent.ToString()); + Assert.Equal(a.TraceStateString, context.TraceState); + + propagator.Extract(null, (object carrier, string fieldName, out string? value) => + { + Assert.Null(carrier); + if (fieldName == "baggage") + { + value = GetFormattedBaggage(a); + } + else + { + value = null; + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + return true; + }, out baggage); + + list = new List>(baggage); + Assert.Equal(2, list.Count); + Assert.Equal(new KeyValuePair("B1", "v1"), list[0]); + Assert.Equal(new KeyValuePair("B2", "v2"), list[1]); + + // + // Test Inject Suppresssion propagator + // + propagator = TextMapPropagator.CreateOutputSuppressionPropagator(); + propagator.Inject(a, null, (object carrier, string fieldName, string value) => + { + Assert.False(true, $"Not expected to have the seeter callback be called."); + }); + + // Extract should continue work + propagator.Extract(null, (object carrier, string fieldName, out string? value) => + { + Assert.Null(carrier); + if (fieldName == "baggage") + { + value = GetFormattedBaggage(a); + } + else + { + value = null; + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + return true; + }, out baggage); + + list = new List>(baggage); + Assert.Equal(2, list.Count); + Assert.Equal(new KeyValuePair("B1", "v1"), list[0]); + Assert.Equal(new KeyValuePair("B2", "v2"), list[1]); + + // + // Test PassThroughPropagator + // + propagator = TextMapPropagator.CreatePassThroughPropagator(); + + Activity.Current = null; + + propagator.Inject(a, null, (object carrier, string fieldName, string value) => + { + Assert.False(true, $"Activity.Current is null. Extract shouldn't be called"); + }); + + using ActivitySource source = new ActivitySource("PropagatorTests"); + using ActivityListener listener = new ActivityListener(); + listener.ShouldListenTo = (activitySource) => object.ReferenceEquals(source, activitySource); + listener.SampleUsingParentId = (ref ActivityCreationOptions activityOptions) => ActivitySamplingResult.AllData; + listener.Sample = (ref ActivityCreationOptions activityOptions) => ActivitySamplingResult.AllData; + ActivitySource.AddActivityListener(listener); + + ActivityContext parentContext = new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded, "states"); + a = source.StartActivity("a", ActivityKind.Client, parentContext); + a.AddBaggage("B1", "v1"); + + propagator.Inject(a, null, (object carrier, string fieldName, string value) => + { + if (fieldName == "traceparent") + { + Assert.Equal(ToString(parentContext), value); + } + else if (fieldName == "tracestate") + { + Assert.Equal(parentContext.TraceState, value); + } + else if (fieldName == "Correlation-Context") + { + Assert.Equal(GetFormattedBaggage(a), value); + } + else + { + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + }); + + Activity b = source.StartActivity("b"); + b.AddBaggage("B2", "v2"); + + propagator.Inject(b, null, (object carrier, string fieldName, string value) => + { + if (fieldName == "traceparent") + { + Assert.Equal(ToString(parentContext), value); + } + else if (fieldName == "tracestate") + { + Assert.Equal(parentContext.TraceState, value); + } + else if (fieldName == "Correlation-Context") + { + Assert.Equal(GetFormattedBaggage(a), value); + } + else + { + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + }); + + Activity.Current = null; + a = new Activity("SomeActivity"); + a.SetIdFormat(ActivityIdFormat.Hierarchical); + a.SetBaggage("B1H", "v1H"); + a.TraceStateString = "traceStateH"; + a.SetParentId("HierarchicalH"); + a.Start(); + + propagator.Inject(b, null, (object carrier, string fieldName, string value) => + { + if (fieldName == "Request-Id") + { + Assert.Equal(a.ParentId, value); + } + else if (fieldName == "tracestate") + { + Assert.Equal(a.TraceStateString, value); + } + else if (fieldName == "Correlation-Context") + { + Assert.Equal(GetFormattedBaggage(a), value); + } + else + { + Assert.False(true, $"{fieldName} Unexpected Field Name"); + } + }); + + b = new Activity("SomeActivityb"); + b.SetIdFormat(ActivityIdFormat.Hierarchical); + b.SetBaggage("B2H", "v2H"); + b.TraceStateString = "traceStateW"; + b.Start(); + + string s1 = Activity.Current.Parent?.OperationName ?? "null"; + + propagator.Inject(b, null, (object carrier, string fieldName, string value) => + { + if (fieldName == "Request-Id") + { + Assert.Equal(a.ParentId, value); + } + else if (fieldName == "tracestate") + { + Assert.Equal(a.TraceStateString, value); + } + else if (fieldName == "Correlation-Context") + { + Assert.Equal(GetFormattedBaggage(a), value); + } + else + { + Assert.False(true, $"{fieldName} Unexpected Field Name with value {value}"); + } + }); + } + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index a2f9daa3feec4..172ae4e8ac6ea 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -12,6 +12,7 @@ + From ec81f5a624d39f6031ed1d4ec28c76dc7647b26f Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 24 Jun 2021 16:07:27 -0700 Subject: [PATCH 6/6] More changes --- ...em.Diagnostics.DiagnosticSourceActivity.cs | 6 ++--- .../System/Diagnostics/TextMapPropagator.cs | 26 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index dfd7499a939db..7f9de8f30d4bf 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -258,7 +258,7 @@ public sealed class ActivityListener : IDisposable public abstract class TextMapPropagator { - public delegate bool PropagatorGetterCallback(object carrier, string fieldName, out string? value); + public delegate void PropagatorGetterCallback(object carrier, string fieldName, out string? value, out System.Collections.Generic.IEnumerable? values); public abstract System.Collections.Generic.IReadOnlyCollection Fields { get; } public abstract bool Inject(System.Diagnostics.Activity activity, object carrier, Action setter); public abstract bool Inject(System.Diagnostics.ActivityContext context, object carrier, Action setter); @@ -266,10 +266,10 @@ public abstract class TextMapPropagator public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out string? id, out string? state); public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out System.Diagnostics.ActivityContext context); public abstract bool Extract(object carrier, PropagatorGetterCallback getter, out System.Collections.Generic.IEnumerable>? baggage); - public static TextMapPropagator Default { get; set; } + public static TextMapPropagator Current { get; set; } public static TextMapPropagator CreateLegacyPropagator() { throw null; } public static TextMapPropagator CreatePassThroughPropagator() { throw null; } - public static TextMapPropagator CreateOutputSuppressionPropagator() { throw null; } + public static TextMapPropagator CreateNoOutputPropagator() { throw null; } public static TextMapPropagator CreateW3CPropagator() { throw null; } } } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs index 8a4743b05a909..334cf3bed94ec 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/TextMapPropagator.cs @@ -9,7 +9,7 @@ namespace System.Diagnostics { public abstract class TextMapPropagator { - public delegate bool PropagatorGetterCallback(object carrier, string fieldName, out string? value); + public delegate void PropagatorGetterCallback(object carrier, string fieldName, out string? value, out IEnumerable? values); public abstract IReadOnlyCollection Fields { get; } @@ -29,13 +29,13 @@ public abstract class TextMapPropagator // Static APIs // - public static TextMapPropagator Default { get; set; } = CreateLegacyPropagator(); + public static TextMapPropagator Current { get; set; } = CreateLegacyPropagator(); // For Microsoft compatibility. e.g., it will propagate Baggage header name as "Correlation-Context" instead of "baggage". public static TextMapPropagator CreateLegacyPropagator() => new LegacyTextMapPropagator(); // Suppress context propagation. - public static TextMapPropagator CreateOutputSuppressionPropagator() => new OutputSuppressionPropagator(); + public static TextMapPropagator CreateNoOutputPropagator() => new OutputSuppressionPropagator(); // propagate only root parent context and ignore any intermediate created context. public static TextMapPropagator CreatePassThroughPropagator() => new PassThroughPropagator(); @@ -209,13 +209,13 @@ internal static bool LegacyExtract(object carrier, PropagatorGetterCallback gett return false; } - getter(carrier, TraceParent, out id); + getter(carrier, TraceParent, out id, out _); if (id is null) { - getter(carrier, RequestId, out id); + getter(carrier, RequestId, out id, out _); } - getter(carrier, TraceState, out state); + getter(carrier, TraceState, out state, out _); return true; } @@ -228,8 +228,8 @@ internal static bool LegacyExtract(object carrier, PropagatorGetterCallback gett return false; } - getter(carrier, TraceParent, out string? traceParent); - getter(carrier, TraceState, out string? traceState); + getter(carrier, TraceParent, out string? traceParent, out _); + getter(carrier, TraceState, out string? traceState, out _); return ActivityContext.TryParse(traceParent, traceState, out context); } @@ -242,10 +242,10 @@ internal static bool LegacyExtract(object carrier, PropagatorGetterCallback gett return false; } - getter(carrier, Baggage, out string? theBaggage); + getter(carrier, Baggage, out string? theBaggage, out _); if (theBaggage is null || !TryExtractBaggage(theBaggage, out baggage)) { - getter(carrier, CorrelationContext, out theBaggage); + getter(carrier, CorrelationContext, out theBaggage, out _); if (theBaggage is not null) { TryExtractBaggage(theBaggage, out baggage); @@ -529,8 +529,8 @@ public override bool Extract(object carrier, PropagatorGetterCallback getter, ou return false; } - getter(carrier, TraceParent, out id); - getter(carrier, TraceState, out state); + getter(carrier, TraceParent, out id, out _); + getter(carrier, TraceState, out state, out _); if (id is not null && !ActivityContext.TryParse(id, state, out ActivityContext context)) { @@ -551,7 +551,7 @@ public override bool Extract(object carrier, PropagatorGetterCallback getter, ou return false; } - getter(carrier, Baggage, out string? theBaggage); + getter(carrier, Baggage, out string? theBaggage, out _); if (theBaggage is not null) {