using System.Security.Cryptography.X509Certificates; using Bit.Core.Settings; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Serilog; using Serilog.Events; using Serilog.Sinks.Syslog; namespace Bit.Core.Utilities; public static class LoggerFactoryExtensions { public static void UseSerilog( this IApplicationBuilder appBuilder, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime, GlobalSettings globalSettings) { if (env.IsDevelopment() && !globalSettings.EnableDevLogging) { return; } applicationLifetime.ApplicationStopped.Register(Log.CloseAndFlush); } public static ILoggingBuilder AddSerilog( this ILoggingBuilder builder, WebHostBuilderContext context, Func filter = null) { var globalSettings = new GlobalSettings(); ConfigurationBinder.Bind(context.Configuration.GetSection("GlobalSettings"), globalSettings); if (context.HostingEnvironment.IsDevelopment() && !globalSettings.EnableDevLogging) { return builder; } bool inclusionPredicate(LogEvent e) { if (filter == null) { return true; } var eventId = e.Properties.ContainsKey("EventId") ? e.Properties["EventId"].ToString() : null; if (eventId?.Contains(Constants.BypassFiltersEventId.ToString()) ?? false) { return true; } return filter(e, globalSettings); } var config = new LoggerConfiguration() .MinimumLevel.Verbose() .Enrich.FromLogContext() .Filter.ByIncludingOnly(inclusionPredicate); if (CoreHelpers.SettingHasValue(globalSettings?.Sentry.Dsn)) { config.WriteTo.Sentry(globalSettings.Sentry.Dsn) .Enrich.FromLogContext() .Enrich.WithProperty("Project", globalSettings.ProjectName); } else if (CoreHelpers.SettingHasValue(globalSettings?.Syslog.Destination)) { // appending sitename to project name to allow easier identification in syslog. var appName = $"{globalSettings.SiteName}-{globalSettings.ProjectName}"; if (globalSettings.Syslog.Destination.Equals("local", StringComparison.OrdinalIgnoreCase)) { config.WriteTo.LocalSyslog(appName); } else if (Uri.TryCreate(globalSettings.Syslog.Destination, UriKind.Absolute, out var syslogAddress)) { // Syslog's standard port is 514 (both UDP and TCP). TLS does not have a standard port, so assume 514. int port = syslogAddress.Port >= 0 ? syslogAddress.Port : 514; if (syslogAddress.Scheme.Equals("udp")) { config.WriteTo.UdpSyslog(syslogAddress.Host, port, appName); } else if (syslogAddress.Scheme.Equals("tcp")) { config.WriteTo.TcpSyslog(syslogAddress.Host, port, appName); } else if (syslogAddress.Scheme.Equals("tls")) { if (CoreHelpers.SettingHasValue(globalSettings.Syslog.CertificateThumbprint)) { config.WriteTo.TcpSyslog(syslogAddress.Host, port, appName, useTls: true, certProvider: new CertificateStoreProvider(StoreName.My, StoreLocation.CurrentUser, globalSettings.Syslog.CertificateThumbprint)); } else { config.WriteTo.TcpSyslog(syslogAddress.Host, port, appName, useTls: true, certProvider: new CertificateFileProvider(globalSettings.Syslog.CertificatePath, globalSettings.Syslog?.CertificatePassword ?? string.Empty)); } } } } else if (CoreHelpers.SettingHasValue(globalSettings.LogDirectory)) { if (globalSettings.LogRollBySizeLimit.HasValue) { var pathFormat = Path.Combine(globalSettings.LogDirectory, $"{globalSettings.ProjectName.ToLowerInvariant()}.log"); if (globalSettings.LogDirectoryByProject) { pathFormat = Path.Combine(globalSettings.LogDirectory, globalSettings.ProjectName, "log.txt"); } config.WriteTo.File(pathFormat, rollOnFileSizeLimit: true, fileSizeLimitBytes: globalSettings.LogRollBySizeLimit); } else { var pathFormat = Path.Combine(globalSettings.LogDirectory, $"{globalSettings.ProjectName.ToLowerInvariant()}_{{Date}}.log"); if (globalSettings.LogDirectoryByProject) { pathFormat = Path.Combine(globalSettings.LogDirectory, globalSettings.ProjectName, "{Date}.txt"); } config.WriteTo.RollingFile(pathFormat); } config .Enrich.FromLogContext() .Enrich.WithProperty("Project", globalSettings.ProjectName); } var serilog = config.CreateLogger(); builder.AddSerilog(serilog); return builder; } }