Skip to content
Open
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 @@ -427,13 +427,19 @@ public IEnumerable<ActivityLink> Links
/// <returns><see cref="Enumerator{T}"/>.</returns>
public Enumerator<ActivityLink> EnumerateLinks() => new Enumerator<ActivityLink>(_links?.First);

/// <summary>
/// Enumerate the baggage attached to this Activity object and its ancestors without allocating.
/// </summary>
/// <returns><see cref="BaggageEnumerator"/>.</returns>
internal BaggageEnumerator EnumerateBaggage() => new BaggageEnumerator(this);

/// <summary>
/// Returns the value of the key-value pair added to the activity with <see cref="AddBaggage(string, string)"/>.
/// Returns null if that key does not exist.
/// </summary>
public string? GetBaggageItem(string key)
{
foreach (KeyValuePair<string, string?> keyValue in Baggage)
foreach (KeyValuePair<string, string?> keyValue in EnumerateBaggage())
if (key == keyValue.Key)
return keyValue.Value;
return null;
Expand Down Expand Up @@ -1600,6 +1606,54 @@ public bool MoveNext()
}
}

/// <summary>
/// Enumerates the baggage stored on this Activity and its ancestors without allocating.
/// Mirrors the semantics of the <see cref="Baggage"/> property, which uses an iterator
/// (allocating a state machine on every call) to walk the same data.
/// </summary>
internal struct BaggageEnumerator
{
// The next Activity (if any) to search for a non-empty baggage list. Always points at an
// Activity whose own baggage list has not yet been consumed by this enumerator.
private Activity? _activity;

// The remaining nodes of the baggage list currently being drained.
private DiagNode<KeyValuePair<string, string?>>? _next;

internal BaggageEnumerator(Activity? activity)
{
_activity = activity;
_next = null;
Current = default;
}

public KeyValuePair<string, string?> Current { get; private set; }

public readonly BaggageEnumerator GetEnumerator() => this;
Comment thread
martincostello marked this conversation as resolved.

public bool MoveNext()
{
while (_next is null)
{
if (_activity is null)
{
return false;
}

BaggageLinkedList? baggage = _activity._baggage;
_activity = _activity.Parent;
if (baggage != null)
{
_next = baggage.First;
}
}

Current = _next.Value;
_next = _next.Next;
return true;
}
}

private sealed class BaggageLinkedList : IEnumerable<KeyValuePair<string, string?>>
{
private DiagNode<KeyValuePair<string, string?>>? _first;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,22 +122,25 @@ public static DistributedContextPropagator Current

// internal stuff

internal static void InjectBaggage(object? carrier, IEnumerable<KeyValuePair<string, string?>> baggage, PropagatorSetterCallback setter)
internal static void InjectBaggage(object? carrier, Activity? activity, PropagatorSetterCallback setter)
{
using (IEnumerator<KeyValuePair<string, string?>> e = baggage.GetEnumerator())
if (activity is null)
{
if (e.MoveNext())
{
StringBuilder baggageList = new StringBuilder();
return;
}

do
{
KeyValuePair<string, string?> item = e.Current;
baggageList.Append(WebUtility.UrlEncode(item.Key)).Append('=').Append(WebUtility.UrlEncode(item.Value)).Append(CommaWithSpace);
} while (e.MoveNext());
Activity.BaggageEnumerator e = activity.EnumerateBaggage();
if (e.MoveNext())
{
StringBuilder baggageList = new StringBuilder();

do
{
KeyValuePair<string, string?> item = e.Current;
baggageList.Append(WebUtility.UrlEncode(item.Key)).Append('=').Append(WebUtility.UrlEncode(item.Value)).Append(CommaWithSpace);
} while (e.MoveNext());

setter(carrier, CorrelationContext, baggageList.ToString(0, baggageList.Length - 2));
}
setter(carrier, CorrelationContext, baggageList.ToString(0, baggageList.Length - 2));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public override void Inject(Activity? activity, object? carrier, PropagatorSette
setter(carrier, RequestId, id);
}

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

public override void ExtractTraceIdAndState(object? carrier, PropagatorGetterCallback? getter, out string? traceId, out string? traceState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public override void Inject(Activity? activity, object? carrier, PropagatorSette
return;
}

GetRootId(out string? parentId, out string? traceState, out bool isW3c, out IEnumerable<KeyValuePair<string, string?>>? baggage);
GetRootId(out string? parentId, out string? traceState, out bool isW3c, out Activity? rootActivity);
if (parentId is null)
{
return;
Expand All @@ -31,17 +31,14 @@ public override void Inject(Activity? activity, object? carrier, PropagatorSette
setter(carrier, TraceState, traceState);
}

if (baggage is not null)
{
InjectBaggage(carrier, baggage, setter);
}
InjectBaggage(carrier, rootActivity, 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)
private static void GetRootId(out string? parentId, out string? traceState, out bool isW3c, out Activity? rootActivity)
{
Activity? activity = Activity.Current;

Expand All @@ -53,7 +50,7 @@ private static void GetRootId(out string? parentId, out string? traceState, out
traceState = activity?.TraceStateString;
parentId = activity?.ParentId ?? activity?.Id;
isW3c = parentId is not null ? Activity.TryConvertIdToContext(parentId, traceState, isRemote: false, out _) : false;
baggage = activity?.Baggage;
rootActivity = activity;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public override void Inject(Activity? activity, object? carrier, PropagatorSette
InjectTraceState(traceState, carrier, setter);
}

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

public override void ExtractTraceIdAndState(object? carrier, PropagatorGetterCallback? getter, out string? traceId, out string? traceState)
Expand Down Expand Up @@ -234,48 +234,46 @@ internal static void InjectTraceState(string traceState, object? carrier, Propag
}
}

internal static void InjectW3CBaggage(object? carrier, IEnumerable<KeyValuePair<string, string?>> baggage, PropagatorSetterCallback setter)
internal static void InjectW3CBaggage(object? carrier, Activity activity, PropagatorSetterCallback setter)
{
using (IEnumerator<KeyValuePair<string, string?>> e = baggage.GetEnumerator())
Activity.BaggageEnumerator e = activity.EnumerateBaggage();
if (e.MoveNext())
{
if (e.MoveNext())
{
ValueStringBuilder encodedBaggage = new ValueStringBuilder(stackalloc char[256]);
ValueStringBuilder encodedBaggage = new ValueStringBuilder(stackalloc char[256]);

int entriesCount = 0;
int lastGoodLength = 0;
int entriesCount = 0;
int lastGoodLength = 0;

do
{
KeyValuePair<string, string?> item = e.Current;
do
{
KeyValuePair<string, string?> item = e.Current;

if (EncodeBaggageKey(item.Key, ref encodedBaggage))
if (EncodeBaggageKey(item.Key, ref encodedBaggage))
{
encodedBaggage.Append(Space);
encodedBaggage.Append(Equal);
encodedBaggage.Append(Space);
if (!string.IsNullOrEmpty(item.Value))
{
encodedBaggage.Append(Space);
encodedBaggage.Append(Equal);
encodedBaggage.Append(Space);
if (!string.IsNullOrEmpty(item.Value))
{
EncodeBaggageValue(item.Value, ref encodedBaggage);
}
encodedBaggage.Append(CommaWithSpace);

entriesCount++;

if (encodedBaggage.Length < MaxBaggageEncodedLength)
{
lastGoodLength = encodedBaggage.Length;
}
EncodeBaggageValue(item.Value, ref encodedBaggage);
}
} while (e.MoveNext() && entriesCount < MaxBaggageEntriesToEmit && encodedBaggage.Length < MaxBaggageEncodedLength);
encodedBaggage.Append(CommaWithSpace);

if (lastGoodLength - 2 > 0)
{
setter(carrier, Baggage, encodedBaggage.AsSpan(0, lastGoodLength - 2).ToString());
entriesCount++;

if (encodedBaggage.Length < MaxBaggageEncodedLength)
{
lastGoodLength = encodedBaggage.Length;
}
}
} while (e.MoveNext() && entriesCount < MaxBaggageEntriesToEmit && encodedBaggage.Length < MaxBaggageEncodedLength);

encodedBaggage.Dispose();
if (lastGoodLength - 2 > 0)
{
setter(carrier, Baggage, encodedBaggage.AsSpan(0, lastGoodLength - 2).ToString());
}

encodedBaggage.Dispose();
}
}

Expand Down
Loading