Opinion: `UseSerilog` should not set the static `Logger.Log` by default (incompatibility with testing, mainly)
See original GitHub issueI noticed that when SerilogWebHostBuilderExtensions.UseSerilog( this IWebHostBuilder builder, Action<WebHostBuilderContext, LoggerConfiguration> configureLogger ) is used then by default preserveStaticLogger == false - which causes this behaviour when called:
- It sets
global::Serilog.Log.Logger(as expected) fromconfigureLogger( new LoggerConfiguration ).CreateLogger(). - Then it registers a
SerilogFactorywhich always usesglobal::Serilog.Log.Loggerto log, instead of caching the logger from theCreateLogger()call (this was unexpected to me and caused problems down the line).
This is incompatible with WebApplicationFactory<TStartup>-based tests in ASP.NET Core testing projects - because xUnit runs tests in parallel by default, which means it creates multiple WebApplicationFactory instances, which will then run through their own UseSerilog call-sites - which then means different WebApplicationFactory instances (each with their own separate Startup and DI container roots) will be sharing the same Serilog.ILogger instances, which is undesirable.
…and generally, using mutable static state is a bad idea anyway (and I think the Serilog project should move the static Logger class to a separate NuGet package so projects don’t unintentionally use it either).
I think the UseSerilog call should be “safe” by default and require users to explicitly opt-in to mutating static state. I propose the two UseSerilog methods be replaced with:
AddSerilog( IWebHostBuilder builder, Serilog.ILogger logger, Boolean dispose = false )- This registers Serilog with DI so it can be injected into pre-
Startuptypes but does not set it as the default ASP.NET CoreMicrosoft.Extensions.Logginglogger.
- This registers Serilog with DI so it can be injected into pre-
UseSerilog( IWebHostBuilder builder, Serilog.ILogger logger, Boolean dispose = false )- Calls
AddSerilogand then sets it as theMELlogger - the same as today.
- Calls
UseSerilog( IWebHostBuilder builder, Action< WebHostBuilderContext, Serilog.LoggerConfiguration > configureLogger )- This would be the same as
UseSerilog( builder, configureLogger, preserveStaticLogger = true );
- This would be the same as
UseSerilog( IWebHostBuilder builder, Action< WebHostBuilderContext, Serilog.LoggerConfiguration > configureLogger, Boolean setStaticLogger = false )- The same as above, with optionally setting
Serilog.Log.Loggerbut will cache the generatedSerilog.ILoggerso the logging system in this host-builder won’t be affected by future changes toSerilog.Log.Logger. - The parameter is also renamed to
setStaticLoggerto make it clear what it actually does - because a name likepreserveStaticLoggersuggests that setting it totruewill not do something rather than doing something.
- The same as above, with optionally setting
AlwaysUseStaticSerilogLogger( IWebHostBuilder builder, Action< WebHostBuilderContext, Serilog.LoggerConfiguration > configureLogger )- Explicitly named extension-method which has the same behaviour as
UseSerilog( builder, configureLogger, preserveStaticLogger: false )does today, and makes it clear that it always usesSerilog.Log.Loggerand does not cache the generatedSerilog.ILogger.
- Explicitly named extension-method which has the same behaviour as
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:8 (4 by maintainers)
Top Related StackOverflow Question
This was confusing for us too and caused some issues…
We used to use the first overload w/ just logger like so (worked great)
we decided to use the other overload… but noticed it wasn’t logging anything…
dug into code and saw that if we don’t pass
preserveStaticLogger: truethen a null logger is passed toSerilogLoggerFactoryand subsequently registered w/ DIWe don’t use the static logger - so maybe that’s the issue - however
preserveStaticLoggerdidn’t seem like something we needed to pass to have a proper logger registered w/ DI… so anyway - now we’re passing inpreserveStaticLoggerso that our DI logger is registeredJust revamped the README, not sure exactly where it’d fit but something along the lines of “pass
preserveStaticLogger: trueto avoid settingLog.Logger.” might do the trick. Open to a PR if anyone has the time to figure out a nice uncluttered way to get this info in 👍