From 755eb19b1cb977d72446d54215d75c22b3b9e9fd Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Thu, 15 Jan 2026 14:22:26 -0500 Subject: [PATCH] feat: ILoggingBuilder.AddSerilog() extension method Context: https://github.com/unoplatform/uno.extensions/issues/3008 Context: https://github.com/unoplatform/uno.extensions/pull/3011 Context: https://github.com/unoplatform/uno.templates/pull/1921 Issue #3008 details that there are two `ILogger` "environments" in a Uno app: * The `App.InitializeLogging()` environment ("NoDI"), and * The environment configured by Dependency Injection methods such as `.UseLogging()` and `.UseSerilog()` ("DI"). The problem is that "DI" logging *cannot* capture log messages produced before the DI environment is built, frequently via `builder.Build()` or `builder.NavigateAsync()`. *A lot* of code can execute before those methods complete. A further problem is that no default template actually configures both environments: if you use `dotnet new unoapp -di False` you get the NoDI `App.InitializeLogging()` environment, which *will not* log messages from the Dependency Injection enviornment. If you use `dotnet new unoapp -preset "recommended"` you get *only* the DI-based logging, thus missing all messages from the NoDI environment. Thus, the idea for "`ILogger` configuration unification": What If instead of having two separate places for logging, we just had one: the NoDI `App.InitializeLogging()` location. This can be made to work via #3011, which updates `HostBuilder.Build()` so that *if* `LogExtensionPoint.AmbientLoggerFactory` is set, it *replaces* the `ILoggerFactory` that `HostBuilder.Build()` normally configures. This allows `App.InitializeLogging()` to also be used in the DI environment. So far, so useful. But what about [Serilog][0]? Serilog is a widely recommended logger library, and the current `.UseSerilog()` extension method *requires* a full Dependency Injection environment: it cannot be invoked within `App.InitializeLogging()`. Try to square this circle by adding a new `ILoggingBuilder.AddSerilog()` extension method. This would allow Serilog to be configured within `App.InitializeLogging()`, helping to support a unified logging setup experience. [0]: https://platform.uno/docs/articles/external/uno.extensions/doc/Overview/Logging/LoggingOverview.html#serilog --- .../Uno.Extensions.Core.WinUI.csproj | 1 + .../HostBuilderExtensions.cs | 4 +- .../LoggingBuilderExtensions.cs | 56 +++++++++++++++++++ .../Uno.Extensions.Logging.Serilog.csproj | 1 + 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 src/Uno.Extensions.Logging.Serilog/LoggingBuilderExtensions.cs diff --git a/src/Uno.Extensions.Core.UI/Uno.Extensions.Core.WinUI.csproj b/src/Uno.Extensions.Core.UI/Uno.Extensions.Core.WinUI.csproj index 71333b57e3..b67a23b6fd 100644 --- a/src/Uno.Extensions.Core.UI/Uno.Extensions.Core.WinUI.csproj +++ b/src/Uno.Extensions.Core.UI/Uno.Extensions.Core.WinUI.csproj @@ -25,6 +25,7 @@ + diff --git a/src/Uno.Extensions.Logging.Serilog/HostBuilderExtensions.cs b/src/Uno.Extensions.Logging.Serilog/HostBuilderExtensions.cs index 27096e10bf..497a47e408 100644 --- a/src/Uno.Extensions.Logging.Serilog/HostBuilderExtensions.cs +++ b/src/Uno.Extensions.Logging.Serilog/HostBuilderExtensions.cs @@ -90,7 +90,7 @@ public static IHostBuilder UseSerilog(this IHostBuilder hostBuilder, }); } - private static LoggerConfiguration AddConsoleLogging(LoggerConfiguration configuration) + internal static LoggerConfiguration AddConsoleLogging(LoggerConfiguration configuration) { #pragma warning disable CA1416 // Validate platform compatibility: The net8.0 version is not used on older versions of OS return configuration @@ -107,7 +107,7 @@ private static LoggerConfiguration AddConsoleLogging(LoggerConfiguration configu #pragma warning restore CA1416 // Validate platform compatibility } - private static LoggerConfiguration AddFileLogging(LoggerConfiguration configuration, string logFilePath) + internal static LoggerConfiguration AddFileLogging(LoggerConfiguration configuration, string logFilePath) { //-:cnd:noEmit #if __ANDROID__ || __IOS__ || NETSTANDARD diff --git a/src/Uno.Extensions.Logging.Serilog/LoggingBuilderExtensions.cs b/src/Uno.Extensions.Logging.Serilog/LoggingBuilderExtensions.cs new file mode 100644 index 0000000000..bc04e01d18 --- /dev/null +++ b/src/Uno.Extensions.Logging.Serilog/LoggingBuilderExtensions.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; + +using Microsoft.Extensions.Logging; + +using Serilog; + +namespace Uno.Extensions; + +/// +/// Extension methods to adjust the scope of collected logs. (log level) +/// +public static class LoggingBuilderExtensions +{ + public static ILoggingBuilder AddSerilog( + this ILoggingBuilder builder, + bool consoleLoggingEnabled = false, + bool fileLoggingEnabled = false, + Action? configureLogger = null) + { +#pragma warning disable CS0436 + var loggerConfiguration = new LoggerConfiguration(); + // loggerConfiguration.ReadFrom.Configuration(context.Configuration); + if (consoleLoggingEnabled) + { + HostBuilderExtensions.AddConsoleLogging(loggerConfiguration); + } + if (fileLoggingEnabled) + { + var logPath = GetLogFilePath(); + if (logPath is not null) + { + HostBuilderExtensions.AddFileLogging(loggerConfiguration, logPath); + } + } +#pragma warning restore CS0436 + configureLogger?.Invoke(loggerConfiguration); + var logger = loggerConfiguration.CreateLogger(); + + builder.AddSerilog(logger); + return builder; + } + + private static string? GetLogFilePath() + { + var logDirectory = ApplicationDataExtensions.DataFolder(); + + if (string.IsNullOrWhiteSpace(logDirectory)) + { + return null; + } + + var assemblyName = PlatformHelper.GetAppAssembly()?.FullName ?? "unologging"; + return Path.Combine(logDirectory, $"{assemblyName}.log"); + } +} diff --git a/src/Uno.Extensions.Logging.Serilog/Uno.Extensions.Logging.Serilog.csproj b/src/Uno.Extensions.Logging.Serilog/Uno.Extensions.Logging.Serilog.csproj index 6e8ea19a78..f95d4bc94d 100644 --- a/src/Uno.Extensions.Logging.Serilog/Uno.Extensions.Logging.Serilog.csproj +++ b/src/Uno.Extensions.Logging.Serilog/Uno.Extensions.Logging.Serilog.csproj @@ -25,6 +25,7 @@ +