Potential design issue with custom ILoggerFactory types and logger providers #1071
Description
I think that the combination of obsoleting ILoggerFactory.AddProvider and allowing custom ILoggerFactory types with IWebHostBuilder.ConfigureLogging<T>()
and ILoggerFactory.UseLoggerFactory(ILoggerFactory)
introduced a (potentially big?!) design issue.
Consider the following scenario:
A logging framework like Serilog will use its own ILoggerFactory
type and offers the following extension method:
public static IWebHostBuilder UseSerilog(this IWebHostBuilder webHostBuilder)
{
SerilogLoggerFactory loggerFactory = new SerilogLoggerFactory();
webHostBuilder.UseLoggerFactory(loggerFactory);
return webHostBuilder;
}
A tracer like Application Insights wants to subscribe to ILogger
-events. It uses the following code to register its services and its logger provider:
public static IWebHostBuilder UseApplicationInsights(this IWebHostBuilder webHostBuilder)
{
webHostBuilder.ConfigureServices(services => { /* add DI services */ };
webHostBuilder.ConfigureLogging<LoggerFactory>((context, loggerFactory) =>
{
loggerFactory.AddApplicationInsightsProvider();
}
return webHostBuilder;
}
An application developer wants to use both and builds his web host with the following code:
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseSerilog()
.UseApplicationInsights()
.Build();
This will result in the Application Insights provider not being registered because the LoggerFactory types don't match. Obviously, a user would have a hard time troubleshooting this.
It also shows a fundamental issue in that tracers are no longer able to reliably register themselves as logging providers. This is a scenario I haven't really thought of in aspnet/Logging#420.
Given this missing link and the fact that LoggerFactory
now already does a lot more with Configuration-based filtering, I no longer think it's useful/good for e.g Serilog to implement a custom ILoggerFactory.
Instead, it might be better to follow one of these solutions:
- Disallow custom
ILoggerFactory
types by using the concrete typeLoggerFactory
everywhere inIWebHostBuilder
. This would still allow people to write derived types while keeping the logic of adding providers intact. The downside of this is that providers still have to depend on theMicrosoft.Extensions.Logging
implementation package. - Undo obsoleting
ILoggerFactory.AddProvider
and useILoggerFactory
inIWebHostBuilder
methods. This way, there would still be anAbstractions
-contract that links loggers and providers together and no-one would have to depend on the implementation package. However, users could still callAddProvider
in regular classes. - Introduce something like
ILoggerProviderFactory
which containsAddProvider()
,AddFilter()
,UseConfiguration
etc. This would completely separate loggers from providers. All logging methods onIWebHostBuilder
would use this interface instead.
The last one might be the cleanest. This type could then be added to DI so that people could use it in Startup.cs
. This would be an easier migration path for users than moving their logging configuration to the WebHostBuilder.
Your thoughts?
I'd be happy to create a PR should you want to do something here!
Edit: I've removed the ConfigureLogging()
examples since they could still use the type constraint. It would just be constrained to the respective type.