diff --git a/src/Serilog.Extensions.Hosting/SerilogLoggingBuilderExtensions.cs b/src/Serilog.Extensions.Hosting/SerilogLoggingBuilderExtensions.cs
index cf8bf04..4efc041 100644
--- a/src/Serilog.Extensions.Hosting/SerilogLoggingBuilderExtensions.cs
+++ b/src/Serilog.Extensions.Hosting/SerilogLoggingBuilderExtensions.cs
@@ -1,4 +1,7 @@
-using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Serilog;
+using Serilog.Extensions.Hosting;
using Serilog.Extensions.Logging;
using System;
using static Serilog.SerilogHostBuilderExtensions;
@@ -21,7 +24,7 @@ public static class SerilogLoggingBuilderExtensions
/// A registered in the Serilog pipeline using the
/// WriteTo.Providers() configuration method, enabling other s to receive events. By
/// default, only Serilog sinks will receive events.
- /// The host builder.
+ /// The logging builder.
public static ILoggingBuilder AddSerilog(
this ILoggingBuilder builder,
Serilog.ILogger logger = null,
@@ -61,5 +64,180 @@ public static ILoggingBuilder AddSerilog(
return builder;
}
+
+ /// Sets Serilog as the logging provider.
+ ///
+ /// A is supplied so that configuration and hosting information can be used.
+ /// The logger will be shut down when application services are disposed.
+ ///
+ /// The logging builder to configure.
+ /// The delegate for configuring the that will be used to construct a .
+ /// Indicates whether to preserve the value of .
+ /// By default, Serilog does not write events to s registered through
+ /// the Microsoft.Extensions.Logging API. Normally, equivalent Serilog sinks are used in place of providers. Specify
+ /// true to write events to all providers.
+ /// If the static is a bootstrap logger (see
+ /// LoggerConfigurationExtensions.CreateBootstrapLogger()), and is
+ /// not specified, the the bootstrap logger will be reconfigured through the supplied delegate, rather than being
+ /// replaced entirely or ignored.
+ /// The logging builder.
+ public static ILoggingBuilder AddSerilogFactory(
+ this ILoggingBuilder builder,
+ Action configureLogger,
+ bool preserveStaticLogger = false,
+ bool writeToProviders = false)
+ {
+ if (builder == null) throw new ArgumentNullException(nameof(builder));
+ if (configureLogger == null) throw new ArgumentNullException(nameof(configureLogger));
+
+ // This check is eager; replacing the bootstrap logger after calling this method is not supported.
+#if !NO_RELOADABLE_LOGGER
+ var reloadable = Log.Logger as ReloadableLogger;
+ var useReload = reloadable != null && !preserveStaticLogger;
+#else
+ const bool useReload = false;
+#endif
+ var services = builder.Services;
+
+ LoggerProviderCollection loggerProviders = null;
+ if (writeToProviders)
+ {
+ loggerProviders = new LoggerProviderCollection();
+ }
+
+ services.AddSingleton(sp =>
+ {
+ Serilog.ILogger logger;
+#if !NO_RELOADABLE_LOGGER
+ if (useReload)
+ {
+ reloadable!.Reload(cfg =>
+ {
+ if (loggerProviders != null)
+ cfg.WriteTo.Providers(loggerProviders);
+
+ configureLogger(sp, cfg);
+ return cfg;
+ });
+
+ logger = reloadable.Freeze();
+ }
+ else
+#endif
+ {
+ var loggerConfiguration = new LoggerConfiguration();
+
+ if (loggerProviders != null)
+ loggerConfiguration.WriteTo.Providers(loggerProviders);
+
+ configureLogger(sp, loggerConfiguration);
+ logger = loggerConfiguration.CreateLogger();
+ }
+
+ return new RegisteredLogger(logger);
+ });
+
+ services.AddSingleton(sp =>
+ {
+ // How can we register the logger, here, but not have MEDI dispose it?
+ // Using the `NullEnricher` hack to prevent disposal.
+ var logger = sp.GetRequiredService().Logger;
+ return logger.ForContext(new NullEnricher());
+ });
+
+ services.AddSingleton(sp =>
+ {
+ var logger = sp.GetRequiredService().Logger;
+
+ Serilog.ILogger registeredLogger = null;
+ if (preserveStaticLogger)
+ {
+ registeredLogger = logger;
+ }
+ else
+ {
+ // Passing a `null` logger to `SerilogLoggerFactory` results in disposal via
+ // `Log.CloseAndFlush()`, which additionally replaces the static logger with a no-op.
+ Log.Logger = logger;
+ }
+
+ var factory = new SerilogLoggerFactory(registeredLogger, !useReload, loggerProviders);
+
+ if (writeToProviders)
+ {
+ foreach (var provider in sp.GetServices())
+ factory.AddProvider(provider);
+ }
+
+ return factory;
+ });
+
+ ConfigureDiagnosticContext(services, preserveStaticLogger);
+
+ return builder;
+ }
+
+ /// Sets Serilog as the logging provider.
+ ///
+ /// A is supplied so that configuration and hosting information can be used.
+ /// The logger will be shut down when application services are disposed.
+ ///
+ /// The logging builder to configure.
+ /// The delegate for configuring the that will be used to construct a .
+ /// Indicates whether to preserve the value of .
+ /// By default, Serilog does not write events to s registered through
+ /// the Microsoft.Extensions.Logging API. Normally, equivalent Serilog sinks are used in place of providers. Specify
+ /// true to write events to all providers.
+ /// The logging builder.
+ public static ILoggingBuilder AddSerilog(
+ this ILoggingBuilder builder,
+ Action configureLogger,
+ bool preserveStaticLogger = false,
+ bool writeToProviders = false)
+ {
+ if (builder == null) throw new ArgumentNullException(nameof(builder));
+ if (configureLogger == null) throw new ArgumentNullException(nameof(configureLogger));
+
+ return AddSerilogFactory(
+ builder,
+ (sp, loggerConfiguration) =>
+ {
+ var configuration = sp.GetRequiredService();
+ configureLogger(configuration, loggerConfiguration);
+ },
+ preserveStaticLogger: preserveStaticLogger,
+ writeToProviders: writeToProviders);
+ }
+
+ /// Sets Serilog as the logging provider.
+ ///
+ /// A is supplied so that configuration and hosting information can be used.
+ /// The logger will be shut down when application services are disposed.
+ ///
+ /// The logging builder to configure.
+ /// The delegate for configuring the that will be used to construct a .
+ /// Indicates whether to preserve the value of .
+ /// By default, Serilog does not write events to s registered through
+ /// the Microsoft.Extensions.Logging API. Normally, equivalent Serilog sinks are used in place of providers. Specify
+ /// true to write events to all providers.
+ /// The logging builder.
+ public static ILoggingBuilder AddSerilog(
+ this ILoggingBuilder builder,
+ Action configureLogger,
+ bool preserveStaticLogger = false,
+ bool writeToProviders = false)
+ {
+ if (builder == null) throw new ArgumentNullException(nameof(builder));
+ if (configureLogger == null) throw new ArgumentNullException(nameof(configureLogger));
+
+ return AddSerilogFactory(
+ builder,
+ (sp, loggerConfiguration) =>
+ {
+ configureLogger(loggerConfiguration);
+ },
+ preserveStaticLogger: preserveStaticLogger,
+ writeToProviders: writeToProviders);
+ }
}
}
\ No newline at end of file
diff --git a/test/Serilog.Extensions.Hosting.Tests/Serilog.Extensions.Hosting.Tests.csproj b/test/Serilog.Extensions.Hosting.Tests/Serilog.Extensions.Hosting.Tests.csproj
index daf9720..77dba55 100644
--- a/test/Serilog.Extensions.Hosting.Tests/Serilog.Extensions.Hosting.Tests.csproj
+++ b/test/Serilog.Extensions.Hosting.Tests/Serilog.Extensions.Hosting.Tests.csproj
@@ -14,6 +14,18 @@
$(DefineConstants);NO_RELOADABLE_LOGGER
+
+
+
+
+
+
+
+ PreserveNewest
+ true
+ PreserveNewest
+
+
@@ -29,6 +41,7 @@
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/Serilog.Extensions.Hosting.Tests/SerilogLoggingBuilderExtensionsTests.cs b/test/Serilog.Extensions.Hosting.Tests/SerilogLoggingBuilderExtensionsTests.cs
index 9f7bbb6..1f71a95 100644
--- a/test/Serilog.Extensions.Hosting.Tests/SerilogLoggingBuilderExtensionsTests.cs
+++ b/test/Serilog.Extensions.Hosting.Tests/SerilogLoggingBuilderExtensionsTests.cs
@@ -10,20 +10,35 @@ namespace Serilog.Extensions.Hosting.Tests;
public class SerilogLoggingBuilderExtensionsTests
{
[Fact]
- public async Task SerilogLoggingBuilderExtensions_AddSerilog_SuccessAsync()
+ public async Task LoggingBuilderExtensions_AddSerilog_SuccessAsync()
{
// Arrange
var builder = WebApplication.CreateBuilder();
- var logger = new LoggerConfiguration()
- .WriteTo.InMemory()
- .CreateLogger();
- builder.Logging.AddSerilog(logger);
+ builder.Logging.AddSerilog(logger => logger.WriteTo.InMemory());
builder.WebHost.UseTestServer();
var app = builder.Build();
// Act
- var message = "Hello World!";
- app.Logger.LogInformation("Hello World!");
+ var message = "Logging in memory";
+ app.Logger.LogInformation(message);
+ await app.StartAsync();
+
+ // Assert
+ InMemorySink.Instance.Should().HaveMessage(message);
+ }
+
+ [Fact]
+ public async Task LoggingBuilderExtensions_AddSerilogWithAppsettings_SuccessAsync()
+ {
+ // Arrange
+ var builder = WebApplication.CreateBuilder();
+ builder.Logging.AddSerilog((appConfig, loggerConfig) => loggerConfig.ReadFrom.Configuration(appConfig));
+ builder.WebHost.UseTestServer();
+ var app = builder.Build();
+
+ // Act
+ var message = "Logging in memory with appsettings.json";
+ app.Logger.LogInformation(message);
await app.StartAsync();
// Assert
diff --git a/test/Serilog.Extensions.Hosting.Tests/appsettings.json b/test/Serilog.Extensions.Hosting.Tests/appsettings.json
new file mode 100644
index 0000000..ba074bc
--- /dev/null
+++ b/test/Serilog.Extensions.Hosting.Tests/appsettings.json
@@ -0,0 +1,16 @@
+{
+ "Serilog": {
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "WriteTo": [
+ {
+ "Name": "InMemory"
+ }
+ ]
+ }
+}
\ No newline at end of file