Skip to content

Commit dacf02b

Browse files
msallinSallin Marc, I212
andauthored
Baggage and Tags for activity tracking options (#46571) (#48722)
Co-authored-by: Sallin Marc, I212 <[email protected]>
1 parent d84e331 commit dacf02b

File tree

7 files changed

+351
-14
lines changed

7 files changed

+351
-14
lines changed

src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ private void WriteScopeInformation(Utf8JsonWriter writer, IExternalScopeProvider
109109
writer.WriteStartArray("Scopes");
110110
scopeProvider.ForEachScope((scope, state) =>
111111
{
112-
if (scope is IEnumerable<KeyValuePair<string, object>> scopes)
112+
if (scope is IEnumerable<KeyValuePair<string, object>> scopeItems)
113113
{
114114
state.WriteStartObject();
115115
state.WriteString("Message", scope.ToString());
116-
foreach (KeyValuePair<string, object> item in scopes)
116+
foreach (KeyValuePair<string, object> item in scopeItems)
117117
{
118118
WriteItem(state, item);
119119
}

src/libraries/Microsoft.Extensions.Logging/ref/Microsoft.Extensions.Logging.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public enum ActivityTrackingOptions
2323
ParentId = 4,
2424
TraceState = 8,
2525
TraceFlags = 16,
26+
Tags = 32,
27+
Baggage = 64
2628
}
2729
public static partial class FilterLoggingBuilderExtensions
2830
{

src/libraries/Microsoft.Extensions.Logging/src/ActivityTrackingOptions.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,38 @@ public enum ActivityTrackingOptions
1616
None = 0x0000,
1717

1818
/// <summary>
19-
/// Span Id wil be included in the logging.
19+
/// Span Id will be included in the logging.
2020
/// </summary>
2121
SpanId = 0x0001,
2222

2323
/// <summary>
24-
/// Trace Id wil be included in the logging.
24+
/// Trace Id will be included in the logging.
2525
/// </summary>
2626
TraceId = 0x0002,
2727

2828
/// <summary>
29-
/// Parent Id wil be included in the logging.
29+
/// Parent Id will be included in the logging.
3030
/// </summary>
3131
ParentId = 0x0004,
3232

3333
/// <summary>
34-
/// Trace State wil be included in the logging.
34+
/// Trace State will be included in the logging.
3535
/// </summary>
3636
TraceState = 0x0008,
3737

3838
/// <summary>
39-
/// Trace flags wil be included in the logging.
39+
/// Trace flags will be included in the logging.
4040
/// </summary>
41-
TraceFlags = 0x0010
41+
TraceFlags = 0x0010,
42+
43+
/// <summary>
44+
/// Tags will be included in the logging.
45+
/// </summary>
46+
Tags = 0x0020,
47+
48+
/// <summary>
49+
/// Items of baggage will be included in the logging.
50+
/// </summary>
51+
Baggage = 0x0040
4252
}
4353
}

src/libraries/Microsoft.Extensions.Logging/src/LoggerFactory.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ public LoggerFactory(IEnumerable<ILoggerProvider> providers, IOptionsMonitor<Log
6666
_factoryOptions = options == null || options.Value == null ? new LoggerFactoryOptions() : options.Value;
6767

6868
const ActivityTrackingOptions ActivityTrackingOptionsMask = ~(ActivityTrackingOptions.SpanId | ActivityTrackingOptions.TraceId | ActivityTrackingOptions.ParentId |
69-
ActivityTrackingOptions.TraceFlags | ActivityTrackingOptions.TraceState);
69+
ActivityTrackingOptions.TraceFlags | ActivityTrackingOptions.TraceState | ActivityTrackingOptions.Tags
70+
| ActivityTrackingOptions.Baggage);
71+
7072

7173
if ((_factoryOptions.ActivityTrackingOptions & ActivityTrackingOptionsMask) != 0)
7274
{

src/libraries/Microsoft.Extensions.Logging/src/LoggerFactoryScopeProvider.cs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Text;
6-
using System.Globalization;
76
using System.Threading;
87
using System.Collections;
98
using System.Diagnostics;
@@ -48,12 +47,47 @@ void Report(Scope current)
4847
}
4948

5049
callback(activityLogScope, state);
50+
51+
// Tags and baggage are opt-in and thus we assume that most of the time it will not be used.
52+
if ((_activityTrackingOption & ActivityTrackingOptions.Tags) != 0
53+
&& activity.TagObjects.GetEnumerator().MoveNext())
54+
{
55+
// As TagObjects is a IEnumerable<KeyValuePair<string, object?>> this can be used directly as a scope.
56+
// We do this to safe the allocation of a wrapper object.
57+
callback(activity.TagObjects, state);
58+
}
59+
60+
if ((_activityTrackingOption & ActivityTrackingOptions.Baggage) != 0)
61+
{
62+
// Only access activity.Baggage as every call leads to an allocation
63+
IEnumerable<KeyValuePair<string, string?>> baggage = activity.Baggage;
64+
if (baggage.GetEnumerator().MoveNext())
65+
{
66+
// For the baggage a wrapper object is necessary because we need to be able to overwrite ToString().
67+
// In contrast to the TagsObject, Baggage doesn't have one underlining type where we can do this overwrite.
68+
ActivityBaggageLogScopeWrapper scope = GetOrCreateActivityBaggageLogScopeWrapper(activity, baggage);
69+
callback(scope, state);
70+
}
71+
}
5172
}
5273
}
5374

5475
Report(_currentScope.Value);
5576
}
5677

78+
private static ActivityBaggageLogScopeWrapper GetOrCreateActivityBaggageLogScopeWrapper(Activity activity, IEnumerable<KeyValuePair<string, string?>> items)
79+
{
80+
const string additionalItemsBaggagePropertyKey = "__ActivityBaggageItemsLogScope__";
81+
var activityBaggageLogScopeWrapper = activity.GetCustomProperty(additionalItemsBaggagePropertyKey) as ActivityBaggageLogScopeWrapper;
82+
if (activityBaggageLogScopeWrapper == null)
83+
{
84+
activityBaggageLogScopeWrapper = new ActivityBaggageLogScopeWrapper(items);
85+
activity.SetCustomProperty(additionalItemsBaggagePropertyKey, activityBaggageLogScopeWrapper);
86+
}
87+
88+
return activityBaggageLogScopeWrapper;
89+
}
90+
5791
public IDisposable Push(object state)
5892
{
5993
Scope parent = _currentScope.Value;
@@ -185,7 +219,59 @@ IEnumerator IEnumerable.GetEnumerator()
185219
return GetEnumerator();
186220
}
187221
}
222+
223+
private class ActivityBaggageLogScopeWrapper : IEnumerable<KeyValuePair<string, string?>>
224+
{
225+
private readonly IEnumerable<KeyValuePair<string, string?>> _items;
226+
227+
private StringBuilder? _stringBuilder;
228+
229+
public ActivityBaggageLogScopeWrapper (IEnumerable<KeyValuePair<string, string?>> items)
230+
{
231+
_items = items;
232+
}
233+
234+
public IEnumerator<KeyValuePair<string, string?>> GetEnumerator()
235+
{
236+
return _items.GetEnumerator();
237+
}
238+
239+
IEnumerator IEnumerable.GetEnumerator()
240+
{
241+
return _items.GetEnumerator();
242+
}
243+
244+
public override string ToString()
245+
{
246+
lock (this)
247+
{
248+
IEnumerator<KeyValuePair<string, string?>> enumerator = _items.GetEnumerator();
249+
if (!enumerator.MoveNext())
250+
{
251+
return string.Empty;
252+
}
253+
254+
_stringBuilder ??= new StringBuilder();
255+
_stringBuilder.Append(enumerator.Current.Key);
256+
_stringBuilder.Append(':');
257+
_stringBuilder.Append(enumerator.Current.Value);
258+
259+
while (enumerator.MoveNext())
260+
{
261+
_stringBuilder.Append(", ");
262+
_stringBuilder.Append(enumerator.Current.Key);
263+
_stringBuilder.Append(':');
264+
_stringBuilder.Append(enumerator.Current.Value);
265+
}
266+
267+
string result = _stringBuilder.ToString();
268+
_stringBuilder.Clear();
269+
return result;
270+
}
271+
}
272+
}
188273
}
274+
189275
internal static class ActivityExtensions
190276
{
191277
public static string GetSpanId(this Activity activity)

0 commit comments

Comments
 (0)