using System.Globalization; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace Bit.Core.Utilities; public static class LoggerFactoryExtensions { /// /// /// /// /// public static IHostBuilder AddSerilogFileLogging(this IHostBuilder hostBuilder) { return hostBuilder.ConfigureLogging((context, logging) => { if (context.HostingEnvironment.IsDevelopment()) { return; } IConfiguration loggingConfiguration; // If they have begun using the new settings location, use that if (!string.IsNullOrEmpty(context.Configuration["Logging:PathFormat"])) { loggingConfiguration = context.Configuration.GetSection("Logging"); } else { var globalSettingsSection = context.Configuration.GetSection("GlobalSettings"); var loggingOptions = new LegacyFileLoggingOptions(); globalSettingsSection.Bind(loggingOptions); if (string.IsNullOrWhiteSpace(loggingOptions.LogDirectory)) { return; } var projectName = loggingOptions.ProjectName ?? context.HostingEnvironment.ApplicationName; string pathFormat; if (loggingOptions.LogRollBySizeLimit.HasValue) { pathFormat = loggingOptions.LogDirectoryByProject ? Path.Combine(loggingOptions.LogDirectory, projectName, "log.txt") : Path.Combine(loggingOptions.LogDirectory, $"{projectName.ToLowerInvariant()}.log"); } else { pathFormat = loggingOptions.LogDirectoryByProject ? Path.Combine(loggingOptions.LogDirectory, projectName, "{Date}.txt") : Path.Combine(loggingOptions.LogDirectory, $"{projectName.ToLowerInvariant()}_{{Date}}.log"); } // We want to rely on Serilog using the configuration section to have customization of the log levels // so we make a custom configuration source for them based on the legacy values and allow overrides from // the new location. loggingConfiguration = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { {"PathFormat", pathFormat}, {"FileSizeLimitBytes", loggingOptions.LogRollBySizeLimit?.ToString(CultureInfo.InvariantCulture)} }) .AddConfiguration(context.Configuration.GetSection("Logging")) .Build(); } logging.AddFile(loggingConfiguration); }); } /// /// Our own proprietary options that we've always supported in `GlobalSettings` configuration section. /// private class LegacyFileLoggingOptions { public string? ProjectName { get; set; } public string? LogDirectory { get; set; } = "/etc/bitwarden/logs"; public bool LogDirectoryByProject { get; set; } = true; public long? LogRollBySizeLimit { get; set; } } }