Exemplo n.º 1
0
        /// <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);
        }