Skip to content
Merged
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 @@ -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