/// <summary> /// Initializes a new instance of the <see cref="SerilogDynamicProvider"/> class. /// Any Serilog settings can be passed in the IConfiguration as needed. /// </summary> /// <param name="configuration">Serilog readable <see cref="IConfiguration"/></param> /// <param name="logger">Serilog logger<see cref="Serilog.Core.Logger"/></param> /// <param name="loggingLevelSwitch">Serilog global log level switch<see cref="LoggingLevelSwitch"/></param> /// <param name="options">Subset of Serilog options managed by wrapper<see cref="ISerilogOptions"/></param> public SerilogDynamicProvider(IConfiguration configuration, ISerilogOptions options = null, Logger logger = null, LoggingLevelSwitch loggingLevelSwitch = null) { if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } _serilogOptions = options ?? new SerilogOptions(configuration); _subLoggerConfiguration = new ConfigurationBuilder() .AddInMemoryCollection(configuration.GetSection(_serilogOptions.ConfigPath) .AsEnumerable().Where((kv) => !_serilogOptions.FullnameExclusions.Any(key => kv.Key.StartsWith(key)))) .Build(); SetFiltersFromOptions(); // Add a level switch that controls the "Default" level at the root if (loggingLevelSwitch == null) { _defaultLevel = _serilogOptions.MinimumLevel.Default; loggingLevelSwitch = new LoggingLevelSwitch(_defaultLevel.Value); } else { _defaultLevel = loggingLevelSwitch.MinimumLevel; } _loggerSwitches.GetOrAdd("Default", loggingLevelSwitch); // Add a global logger that will be the root of all other added loggers _globalLogger = logger ?? SerilogConfigurationExtensions.GetDefaultSerilogConfiguration(configuration) .MinimumLevel.ControlledBy(loggingLevelSwitch) .CreateLogger(); }
/// <summary> /// Configure Serilog as the <see cref="IDynamicLoggerProvider"/> to enable dynamically controlling log levels via management endpoints /// </summary> /// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure</param> /// <param name="configureLogger">The delegate for configuring the <see cref="DynamicLoggerConfiguration" /> that will be used to construct a <see cref="Serilog.Core.Logger" /></param> /// <param name="preserveStaticLogger">Indicates whether to preserve the value of <see cref="Log.Logger"/>.</param> /// <param name="preserveDefaultConsole">When true, do not remove Microsoft's ConsoleLoggerProvider</param> /// <returns>The <see cref="IWebHostBuilder"/></returns> public static IWebHostBuilder AddDynamicSerilog( this IWebHostBuilder hostBuilder, Action <WebHostBuilderContext, LoggerConfiguration> configureLogger = null, bool preserveStaticLogger = false, bool preserveDefaultConsole = false) { return(hostBuilder .ConfigureLogging((hostContext, logBuilder) => { var loggerConfiguration = SerilogConfigurationExtensions.GetDefaultSerilogConfiguration(hostContext.Configuration); if (configureLogger is object) { configureLogger(hostContext, loggerConfiguration); } logBuilder.AddDynamicSerilog(loggerConfiguration, preserveStaticLogger, preserveDefaultConsole); })); }
/// <summary> /// Add Serilog, wrapped in a <see cref="IDynamicLoggerProvider"/> that supports /// dynamically controlling the minimum log level via management endpoints. Will add a Console sink if <paramref name="loggerConfiguration"/> is not provided. /// </summary> /// <param name="builder">The <see cref="ILoggingBuilder"/> for configuring the LoggerFactory</param> /// <param name="loggerConfiguration">An initial <see cref="LoggerConfiguration"/></param> /// <param name="preserveStaticLogger">Indicates whether to preserve the value of <see cref="Log.Logger"/>.</param> /// <param name="preserveDefaultConsole">When true, do not remove Microsoft's ConsoleLoggerProvider</param> /// <returns>The configured <see cref="ILoggingBuilder"/></returns> public static ILoggingBuilder AddDynamicSerilog(this ILoggingBuilder builder, LoggerConfiguration loggerConfiguration, bool preserveStaticLogger = false, bool preserveDefaultConsole = false) { if (builder.Services.Any(sd => sd.ServiceType == typeof(IDynamicLoggerProvider))) { throw new InvalidOperationException("An IDynamicLoggerProvider has already been configured! Call 'AddDynamicSerilog' earlier in program.cs (before adding Actuators) or remove duplicate IDynamicLoggerProvider entries."); } if (!preserveDefaultConsole) { var defaultConsoleDescriptor = builder.Services.FirstOrDefault(d => d.ImplementationType == typeof(ConsoleLoggerProvider)); if (defaultConsoleDescriptor != null) { builder.Services.Remove(defaultConsoleDescriptor); } } var configuration = builder.Services.BuildServiceProvider().GetRequiredService <IConfiguration>(); var serilogOptions = new SerilogOptions(configuration); loggerConfiguration ??= SerilogConfigurationExtensions.GetDefaultSerilogConfiguration(configuration); // Add a level switch that controls the "Default" level at the root var levelSwitch = new LoggingLevelSwitch(serilogOptions.MinimumLevel.Default); loggerConfiguration.MinimumLevel.ControlledBy(levelSwitch); var logger = loggerConfiguration.CreateLogger(); if (!preserveStaticLogger) { Log.Logger = logger; } builder.Services.AddSingleton <ISerilogOptions>(serilogOptions); builder.Services.AddSingleton(levelSwitch); builder.Services.AddSingleton(logger); builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton <ILoggerProvider, SerilogDynamicProvider>()); builder.Services.AddSingleton((p) => p.GetServices <ILoggerProvider>().OfType <IDynamicLoggerProvider>().SingleOrDefault()); return(builder); }