Skip to content

Commit 083f85b

Browse files
authored
Enable Activity tracking on generic host (#37892)
* Enable Activity tracking on generic host * Add test * Remove trailing whitespace * Bad merge * React to W3C format change * Remove conditional fact
1 parent ab119ad commit 083f85b

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

src/libraries/Microsoft.Extensions.Hosting/src/Host.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,14 @@ public static IHostBuilder CreateDefaultBuilder(string[] args)
115115
// Add the EventLogLoggerProvider on windows machines
116116
logging.AddEventLog();
117117
}
118+
119+
logging.Configure(options =>
120+
{
121+
options.ActivityTrackingOptions = ActivityTrackingOptions.SpanId
122+
| ActivityTrackingOptions.TraceId
123+
| ActivityTrackingOptions.ParentId;
124+
});
125+
118126
})
119127
.UseDefaultServiceProvider((context, options) =>
120128
{

src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostTests.cs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Concurrent;
77
using System.Collections.Generic;
8+
using System.Diagnostics;
89
using System.Diagnostics.Tracing;
910
using System.IO;
1011
using System.Linq;
@@ -60,6 +61,45 @@ public void CreateDefaultBuilder_RegistersEventSourceLogger()
6061
args.Payload.OfType<string>().Any(p => p.Contains("Request starting")));
6162
}
6263

64+
[Fact]
65+
[ActiveIssue("https://github.com/dotnet/runtime/issues/34580", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
66+
public void CreateDefaultBuilder_EnablesActivityTracking()
67+
{
68+
var parentActivity = new Activity("ParentActivity");
69+
parentActivity.Start();
70+
var activity = new Activity("ChildActivity");
71+
activity.Start();
72+
var id = activity.Id;
73+
var logger = new ScopeDelegateLogger((scopeObjectList) =>
74+
{
75+
Assert.Equal(1, scopeObjectList.Count);
76+
var activityDictionary = (scopeObjectList.FirstOrDefault() as IEnumerable<KeyValuePair<string, object>>)
77+
.ToDictionary(x => x.Key, x => x.Value);
78+
switch (activity.IdFormat)
79+
{
80+
case ActivityIdFormat.Hierarchical:
81+
Assert.Equal(activity.Id, activityDictionary["SpanId"]);
82+
Assert.Equal(activity.RootId, activityDictionary["TraceId"]);
83+
Assert.Equal(activity.ParentId, activityDictionary["ParentId"]);
84+
break;
85+
case ActivityIdFormat.W3C:
86+
Assert.Equal(activity.SpanId.ToHexString(), activityDictionary["SpanId"]);
87+
Assert.Equal(activity.TraceId.ToHexString(), activityDictionary["TraceId"]);
88+
Assert.Equal(activity.ParentSpanId.ToHexString(), activityDictionary["ParentId"]);
89+
break;
90+
}
91+
});
92+
var loggerProvider = new ScopeDelegateLoggerProvider(logger);
93+
var host = Host.CreateDefaultBuilder()
94+
.ConfigureLogging(logging =>
95+
{
96+
logging.AddProvider(loggerProvider);
97+
})
98+
.Build();
99+
100+
logger.LogInformation("Dummy log");
101+
}
102+
63103
[Fact]
64104
[ActiveIssue("https://github.com/dotnet/runtime/issues/34580", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
65105
public void CreateDefaultBuilder_EnablesScopeValidation()
@@ -178,6 +218,65 @@ public ServiceB(ServiceC c)
178218

179219
internal class ServiceC { }
180220

221+
private class ScopeDelegateLoggerProvider : ILoggerProvider, ISupportExternalScope
222+
{
223+
private ScopeDelegateLogger _logger;
224+
private IExternalScopeProvider _scopeProvider;
225+
public ScopeDelegateLoggerProvider(ScopeDelegateLogger logger)
226+
{
227+
_logger = logger;
228+
}
229+
public ILogger CreateLogger(string categoryName)
230+
{
231+
_logger.ScopeProvider = _scopeProvider;
232+
return _logger;
233+
}
234+
235+
public void Dispose()
236+
{
237+
}
238+
239+
public void SetScopeProvider(IExternalScopeProvider scopeProvider)
240+
{
241+
_scopeProvider = scopeProvider;
242+
}
243+
}
244+
245+
private class ScopeDelegateLogger : ILogger
246+
{
247+
private Action<List<object>> _logDelegate;
248+
internal IExternalScopeProvider ScopeProvider { get; set; }
249+
public ScopeDelegateLogger(Action<List<object>> logDelegate)
250+
{
251+
_logDelegate = logDelegate;
252+
}
253+
public IDisposable BeginScope<TState>(TState state)
254+
{
255+
Scopes.Add(state);
256+
return new Scope();
257+
}
258+
259+
public List<object> Scopes { get; set; } = new List<object>();
260+
261+
public bool IsEnabled(LogLevel logLevel) => true;
262+
263+
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
264+
{
265+
ScopeProvider.ForEachScope((scopeObject, state) =>
266+
{
267+
Scopes.Add(scopeObject);
268+
}, 0);
269+
_logDelegate(Scopes);
270+
}
271+
272+
private class Scope : IDisposable
273+
{
274+
public void Dispose()
275+
{
276+
}
277+
}
278+
}
279+
181280
private class TestEventListener : EventListener
182281
{
183282
private volatile bool _disposed;

0 commit comments

Comments
 (0)