Skip to content

Commit

Permalink
Propagators Support (#55419)
Browse files Browse the repository at this point in the history
  • Loading branch information
tarekgh authored Jul 10, 2021
1 parent fce412b commit 8fdc829
Show file tree
Hide file tree
Showing 8 changed files with 1,095 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,20 @@ public sealed class ActivityListener : IDisposable
public System.Diagnostics.SampleActivity<string>? SampleUsingParentId { get { throw null; } set { throw null; } }
public System.Diagnostics.SampleActivity<ActivityContext>? Sample { get { throw null; } set { throw null; } }
public void Dispose() { throw null; }
}
}
public abstract class TextMapPropagator
{
public delegate void PropagatorGetterCallback(object? carrier, string fieldName, out string? fieldValue, out System.Collections.Generic.IEnumerable<string>? fieldValues);
public delegate void PropagatorSetterCallback(object? carrier, string fieldName, string fieldValue);
public abstract System.Collections.Generic.IReadOnlyCollection<string> Fields { get; }
public abstract void Inject(Activity? activity, object? carrier, PropagatorSetterCallback? setter);
public abstract void ExtractTraceIdAndState(object? carrier, PropagatorGetterCallback? getter, out string? traceId, out string? traceState);
public abstract System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string?>>? ExtractBaggage(object? carrier, PropagatorGetterCallback? getter);
public static TextMapPropagator Current { get; set; }
public static TextMapPropagator CreateDefaultPropagator() { throw null; }
public static TextMapPropagator CreatePassThroughPropagator() { throw null; }
public static TextMapPropagator CreateNoOutputPropagator() { throw null; }
}
}

namespace System.Diagnostics.Metrics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@
<Compile Include="System\Diagnostics\ActivitySource.cs" />
<Compile Include="System\Diagnostics\DiagnosticSourceActivity.cs" />
<Compile Include="System\Diagnostics\DiagLinkedList.cs" />
<Compile Include="System\Diagnostics\LegacyPropagator.cs" />
<Compile Include="System\Diagnostics\NoOutputPropagator.cs" />
<Compile Include="System\Diagnostics\PassThroughPropagator.cs" />
<Compile Include="System\Diagnostics\RandomNumberGenerator.cs" />
<Compile Include="System\Diagnostics\TextMapPropagator.cs" />
<Compile Include="System\Diagnostics\Metrics\AggregationManager.cs" />
<Compile Include="System\Diagnostics\Metrics\Aggregator.cs" />
<Compile Include="System\Diagnostics\Metrics\AggregatorStore.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// 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 System.Collections.ObjectModel;

namespace System.Diagnostics
{
internal sealed class LegacyPropagator : TextMapPropagator
{
internal static TextMapPropagator Instance { get; } = new LegacyPropagator();

public override IReadOnlyCollection<string> Fields { get; } = new ReadOnlyCollection<string>(new[] { TraceParent, RequestId, TraceState, Baggage, CorrelationContext });

public override void Inject(Activity? activity, object? carrier, PropagatorSetterCallback? setter)
{
if (activity is null || setter is null)
{
return;
}

string? id = activity.Id;
if (id is null)
{
return;
}

if (activity.IdFormat == ActivityIdFormat.W3C)
{
setter(carrier, TraceParent, id);
if (!string.IsNullOrEmpty(activity.TraceStateString))
{
setter(carrier, TraceState, activity.TraceStateString);
}
}
else
{
setter(carrier, RequestId, id);
}

InjectBaggage(carrier, activity.Baggage, setter);
}

public override void ExtractTraceIdAndState(object? carrier, PropagatorGetterCallback? getter, out string? traceId, out string? traceState)
{
if (getter is null)
{
traceId = null;
traceState = null;
return;
}

getter(carrier, TraceParent, out traceId, out _);
if (traceId is null)
{
getter(carrier, RequestId, out traceId, out _);
}

getter(carrier, TraceState, out traceState, out _);
}

public override IEnumerable<KeyValuePair<string, string?>>? ExtractBaggage(object? carrier, PropagatorGetterCallback? getter)
{
if (getter is null)
{
return null;
}

getter(carrier, Baggage, out string? theBaggage, out _);

IEnumerable<KeyValuePair<string, string?>>? baggage = null;
if (theBaggage is null || !TryExtractBaggage(theBaggage, out baggage))
{
getter(carrier, CorrelationContext, out theBaggage, out _);
if (theBaggage is not null)
{
TryExtractBaggage(theBaggage, out baggage);
}
}

return baggage;
}

internal static bool TryExtractBaggage(string baggageString, out IEnumerable<KeyValuePair<string, string?>>? baggage)
{
baggage = null;
List<KeyValuePair<string, string?>>? baggageList = null;

if (string.IsNullOrEmpty(baggageString))
{
return true;
}

int currentIndex = 0;

do
{
// Skip spaces
while (currentIndex < baggageString.Length && (baggageString[currentIndex] == Space || baggageString[currentIndex] == Tab))
{
currentIndex++;
}

if (currentIndex >= baggageString.Length)
{
break; // No Key exist
}

int keyStart = currentIndex;

// Search end of the key
while (currentIndex < baggageString.Length && baggageString[currentIndex] != Space && baggageString[currentIndex] != Tab && baggageString[currentIndex] != '=')
{
currentIndex++;
}

if (currentIndex >= baggageString.Length)
{
break;
}

int keyEnd = currentIndex;

if (baggageString[currentIndex] != '=')
{
// Skip Spaces
while (currentIndex < baggageString.Length && (baggageString[currentIndex] == Space || baggageString[currentIndex] == Tab))
{
currentIndex++;
}

if (currentIndex >= baggageString.Length)
{
break; // Wrong key format
}

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();

// Insert in reverse order for asp.net compatability.
baggageList.Insert(0, new KeyValuePair<string, string?>(
WebUtility.UrlDecode(baggageString.Substring(keyStart, keyEnd - keyStart)).Trim(s_trimmingSpaceCharacters),
WebUtility.UrlDecode(baggageString.Substring(valueStart, currentIndex - valueStart)).Trim(s_trimmingSpaceCharacters)));
}

// 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;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;

namespace System.Diagnostics
{
internal sealed class NoOutputPropagator : TextMapPropagator
{
internal static TextMapPropagator Instance { get; } = new NoOutputPropagator();

public override IReadOnlyCollection<string> Fields { get; } = LegacyPropagator.Instance.Fields;

public override void Inject(Activity? activity, object? carrier, PropagatorSetterCallback? setter)
{
// nothing to do.
}

public override void ExtractTraceIdAndState(object? carrier, PropagatorGetterCallback? getter, out string? traceId, out string? traceState) => LegacyPropagator.Instance.ExtractTraceIdAndState(carrier, getter, out traceId, out traceState);

public override IEnumerable<KeyValuePair<string, string?>>? ExtractBaggage(object? carrier, PropagatorGetterCallback? getter) => LegacyPropagator.Instance.ExtractBaggage(carrier, getter);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;

namespace System.Diagnostics
{
internal sealed class PassThroughPropagator : TextMapPropagator
{
internal static TextMapPropagator Instance { get; } = new PassThroughPropagator();

public override IReadOnlyCollection<string> Fields { get; } = LegacyPropagator.Instance.Fields;

public override void Inject(Activity? activity, object? carrier, PropagatorSetterCallback? setter)
{
if (setter is null)
{
return;
}

GetRootId(out string? parentId, out string? traceState, out bool isW3c, out IEnumerable<KeyValuePair<string, string?>>? baggage);
if (parentId is null)
{
return;
}

setter(carrier, isW3c ? TraceParent : RequestId, parentId);

if (!string.IsNullOrEmpty(traceState))
{
setter(carrier, TraceState, traceState);
}

if (baggage is not null)
{
InjectBaggage(carrier, baggage, setter);
}
}

public override void ExtractTraceIdAndState(object? carrier, PropagatorGetterCallback? getter, out string? traceId, out string? traceState) => LegacyPropagator.Instance.ExtractTraceIdAndState(carrier, getter, out traceId, out traceState);

public override IEnumerable<KeyValuePair<string, string?>>? ExtractBaggage(object? carrier, PropagatorGetterCallback? getter) => LegacyPropagator.Instance.ExtractBaggage(carrier, getter);

private static void GetRootId(out string? parentId, out string? traceState, out bool isW3c, out IEnumerable<KeyValuePair<string, string?>>? baggage)
{
Activity? activity = Activity.Current;

while (activity?.Parent is Activity parent)
{
activity = parent;
}

traceState = activity?.TraceStateString;
parentId = activity?.ParentId ?? activity?.Id;
isW3c = parentId is not null ? Activity.TryConvertIdToContext(parentId, traceState, out _) : false;
baggage = activity?.Baggage;
}
}
}
Loading

0 comments on commit 8fdc829

Please sign in to comment.