My Serilog configuration code looks like this:
Log.Logger = new LoggerConfiguration()
.Enrich.WithExceptionDetails()
.Enrich.FromLogContext()
.MinimumLevel.Warning()
// .MinimumLevel.Override("Microsoft", LogEventLevel.Verbose)
// .MinimumLevel.Override("System", LogEventLevel.Verbose)
// .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Verbose)
.WriteTo.Console( outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Literate )
// .WriteTo.File()
.CreateLogger();
I'd like to change this configuration at runtime, unfortunately because Serilog uses a "fluent" style of API it makes it somewhat messy. For example, if I want to enable or disable console and file logging at runtime:
Boolean enableConsoleLogging = ...
Boolean enableFileLogging = ...
LoggerConfiguration builder = new LoggerConfiguration()
.Enrich.WithExceptionDetails()
.Enrich.FromLogContext()
.MinimumLevel.Warning();
if( enableConsoleLogging )
{
builder = builder
.WriteTo.Console( outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Literate )
}
if( enableFileLogging )
{
builder = builder
.WriteTo.File( ... )
}
Log.Logger = builder.CreateLogger();
...which is not exactly elegant.
I know I could add my own If
extension method (but I'm not keen on extending an existing API design like that, even if it does look prettier):
Log.Logger = new LoggerConfiguration()
.Enrich.WithExceptionDetails()
.Enrich.FromLogContext()
.MinimumLevel.Warning()
.If( enableConsoleLogging, b => b.WriteTo.Console( outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Literate ) )
.If( enableFileLogging, b => b.WriteTo.File( ... ) )
.CreateLogger();
public static LoggerConfiguration If( this LoggerConfiguration cfg, Boolean test, Func<LoggerConfiguration,LoggerConfiguration> action )
{
if( test ) return action( cfg );
else return cfg;
}
What alternatives exist to toggle different Serilog options at runtime? Are there any approaches that can be used with other "Fluent" APIs?
I think to make it elegant and still do it in code, you do have to extend the API and create your own extension methods that encapsulate the condition checks and update the builder with the correct sink and parameters.
Something like
On a different note, have you considered using
Serilog.Settings.AppSettings
orSerilog.Settings.Configuration
instead? The configuration in code gets much cleaner, and you can add/remove sinks in the configuration file as you wish...