Remove deprecated logging methods (#6516)

This commit is contained in:
Justin Baur 2025-11-21 14:39:26 -05:00 committed by GitHub
parent 042279682a
commit fdfec0ac4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 93 additions and 688 deletions

View File

@ -90,11 +90,7 @@
"Microsoft.AspNetCore.Mvc.Testing",
"Newtonsoft.Json",
"NSubstitute",
"Sentry.Serilog",
"Serilog.AspNetCore",
"Serilog.Extensions.Logging",
"Serilog.Extensions.Logging.File",
"Serilog.Sinks.SyslogMessages",
"Stripe.net",
"Swashbuckle.AspNetCore",
"Swashbuckle.AspNetCore.SwaggerGen",

View File

@ -11,21 +11,8 @@ public class Program
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureLogging((hostingContext, logging) =>
logging.AddSerilog(hostingContext, (e, globalSettings) =>
{
var context = e.Properties["SourceContext"].ToString();
if (e.Properties.TryGetValue("RequestPath", out var requestPath) &&
!string.IsNullOrWhiteSpace(requestPath?.ToString()) &&
(context.Contains(".Server.Kestrel") || context.Contains(".Core.IISHttpServer")))
{
return false;
}
return e.Level >= globalSettings.MinLogLevel.ScimSettings.Default;
}));
})
.AddSerilogFileLogging()
.Build()
.Run();
}

View File

@ -94,11 +94,8 @@ public class Startup
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IHostApplicationLifetime appLifetime,
GlobalSettings globalSettings)
{
app.UseSerilog(env, appLifetime, globalSettings);
// Add general security headers
app.UseMiddleware<SecurityHeadersMiddleware>();

View File

@ -30,9 +30,6 @@
"connectionString": "SECRET",
"applicationCacheTopicName": "SECRET"
},
"sentry": {
"dsn": "SECRET"
},
"notificationHub": {
"connectionString": "SECRET",
"hubName": "SECRET"

View File

@ -1,5 +1,4 @@
using Bit.Core.Utilities;
using Serilog;
namespace Bit.Sso;
@ -13,19 +12,8 @@ public class Program
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureLogging((hostingContext, logging) =>
logging.AddSerilog(hostingContext, (e, globalSettings) =>
{
var context = e.Properties["SourceContext"].ToString();
if (e.Properties.TryGetValue("RequestPath", out var requestPath) &&
!string.IsNullOrWhiteSpace(requestPath?.ToString()) &&
(context.Contains(".Server.Kestrel") || context.Contains(".Core.IISHttpServer")))
{
return false;
}
return e.Level >= globalSettings.MinLogLevel.SsoSettings.Default;
}));
})
.AddSerilogFileLogging()
.Build()
.Run();
}

View File

@ -100,8 +100,6 @@ public class Startup
IdentityModelEventSource.ShowPII = true;
}
app.UseSerilog(env, appLifetime, globalSettings);
// Add general security headers
app.UseMiddleware<SecurityHeadersMiddleware>();

View File

@ -16,19 +16,8 @@ public class Program
o.Limits.MaxRequestLineSize = 20_000;
});
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureLogging((hostingContext, logging) =>
logging.AddSerilog(hostingContext, (e, globalSettings) =>
{
var context = e.Properties["SourceContext"].ToString();
if (e.Properties.TryGetValue("RequestPath", out var requestPath) &&
!string.IsNullOrWhiteSpace(requestPath?.ToString()) &&
(context.Contains(".Server.Kestrel") || context.Contains(".Core.IISHttpServer")))
{
return false;
}
return e.Level >= globalSettings.MinLogLevel.AdminSettings.Default;
}));
})
.AddSerilogFileLogging()
.Build()
.Run();
}

View File

@ -132,11 +132,8 @@ public class Startup
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IHostApplicationLifetime appLifetime,
GlobalSettings globalSettings)
{
app.UseSerilog(env, appLifetime, globalSettings);
// Add general security headers
app.UseMiddleware<SecurityHeadersMiddleware>();

View File

@ -1,9 +1,4 @@
// FIXME: Update this file to be null safe and then delete the line below
#nullable disable
using AspNetCoreRateLimit;
using Bit.Core.Utilities;
using Microsoft.IdentityModel.Tokens;
using Bit.Core.Utilities;
namespace Bit.Api;
@ -17,32 +12,8 @@ public class Program
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureLogging((hostingContext, logging) =>
logging.AddSerilog(hostingContext, (e, globalSettings) =>
{
var context = e.Properties["SourceContext"].ToString();
if (e.Exception != null &&
(e.Exception.GetType() == typeof(SecurityTokenValidationException) ||
e.Exception.Message == "Bad security stamp."))
{
return false;
}
if (
context.Contains(typeof(IpRateLimitMiddleware).FullName))
{
return e.Level >= globalSettings.MinLogLevel.ApiSettings.IpRateLimit;
}
if (context.Contains("Duende.IdentityServer.Validation.TokenValidator") ||
context.Contains("Duende.IdentityServer.Validation.TokenRequestValidator"))
{
return e.Level >= globalSettings.MinLogLevel.ApiSettings.IdentityToken;
}
return e.Level >= globalSettings.MinLogLevel.ApiSettings.Default;
}));
})
.AddSerilogFileLogging()
.Build()
.Run();
}

View File

@ -234,12 +234,10 @@ public class Startup
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IHostApplicationLifetime appLifetime,
GlobalSettings globalSettings,
ILogger<Startup> logger)
{
IdentityModelEventSource.ShowPII = true;
app.UseSerilog(env, appLifetime, globalSettings);
// Add general security headers
app.UseMiddleware<SecurityHeadersMiddleware>();

View File

@ -32,9 +32,6 @@
"send": {
"connectionString": "SECRET"
},
"sentry": {
"dsn": "SECRET"
},
"notificationHub": {
"connectionString": "SECRET",
"hubName": "SECRET"

View File

@ -11,25 +11,8 @@ public class Program
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureLogging((hostingContext, logging) =>
logging.AddSerilog(hostingContext, (e, globalSettings) =>
{
var context = e.Properties["SourceContext"].ToString();
if (context.StartsWith("\"Bit.Billing.Jobs") || context.StartsWith("\"Bit.Core.Jobs"))
{
return e.Level >= globalSettings.MinLogLevel.BillingSettings.Jobs;
}
if (e.Properties.TryGetValue("RequestPath", out var requestPath) &&
!string.IsNullOrWhiteSpace(requestPath?.ToString()) &&
(context.Contains(".Server.Kestrel") || context.Contains(".Core.IISHttpServer")))
{
return false;
}
return e.Level >= globalSettings.MinLogLevel.BillingSettings.Default;
}));
})
.AddSerilogFileLogging()
.Build()
.Run();
}

View File

@ -10,7 +10,6 @@ using Bit.Core.Billing.Extensions;
using Bit.Core.Context;
using Bit.Core.SecretsManager.Repositories;
using Bit.Core.SecretsManager.Repositories.Noop;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Bit.SharedWeb.Utilities;
using Microsoft.Extensions.DependencyInjection.Extensions;
@ -129,12 +128,8 @@ public class Startup
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IHostApplicationLifetime appLifetime,
GlobalSettings globalSettings)
IWebHostEnvironment env)
{
app.UseSerilog(env, appLifetime, globalSettings);
// Add general security headers
app.UseMiddleware<SecurityHeadersMiddleware>();

View File

@ -30,9 +30,6 @@
"connectionString": "SECRET",
"applicationCacheTopicName": "SECRET"
},
"sentry": {
"dsn": "SECRET"
},
"notificationHub": {
"connectionString": "SECRET",
"hubName": "SECRET"

View File

@ -50,13 +50,9 @@
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="8.0.10" />
<PackageReference Include="OneOf" Version="3.0.271" />
<PackageReference Include="SendGrid" Version="9.29.3" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<PackageReference Include="Sentry.Serilog" Version="5.0.0" />
<PackageReference Include="Duende.IdentityServer" Version="7.2.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog.Sinks.SyslogMessages" Version="4.0.0" />
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="Braintree" Version="5.28.0" />
<PackageReference Include="Stripe.net" Version="48.5.0" />

View File

@ -2,14 +2,12 @@
#nullable disable
using Bit.Core.Auth.Settings;
using Bit.Core.Settings.LoggingSettings;
namespace Bit.Core.Settings;
public class GlobalSettings : IGlobalSettings
{
private string _mailTemplateDirectory;
private string _logDirectory;
private string _licenseDirectory;
public GlobalSettings()
@ -25,14 +23,6 @@ public class GlobalSettings : IGlobalSettings
public virtual string KnownProxies { get; set; }
public virtual string SiteName { get; set; }
public virtual string ProjectName { get; set; }
public virtual string LogDirectory
{
get => BuildDirectory(_logDirectory, "/logs");
set => _logDirectory = value;
}
public virtual bool LogDirectoryByProject { get; set; } = true;
public virtual long? LogRollBySizeLimit { get; set; }
public virtual bool EnableDevLogging { get; set; } = false;
public virtual string LicenseDirectory
{
get => BuildDirectory(_licenseDirectory, "/core/licenses");
@ -73,9 +63,6 @@ public class GlobalSettings : IGlobalSettings
public virtual FileStorageSettings Send { get; set; }
public virtual IdentityServerSettings IdentityServer { get; set; } = new IdentityServerSettings();
public virtual DataProtectionSettings DataProtection { get; set; }
public virtual SentrySettings Sentry { get; set; } = new SentrySettings();
public virtual SyslogSettings Syslog { get; set; } = new SyslogSettings();
public virtual ILogLevelSettings MinLogLevel { get; set; } = new LogLevelSettings();
public virtual NotificationHubPoolSettings NotificationHubPool { get; set; } = new();
public virtual YubicoSettings Yubico { get; set; } = new YubicoSettings();
public virtual DuoSettings Duo { get; set; } = new DuoSettings();
@ -548,59 +535,11 @@ public class GlobalSettings : IGlobalSettings
}
}
public class SentrySettings
{
public string Dsn { get; set; }
}
public class NotificationsSettings : ConnectionStringSettings
{
public string RedisConnectionString { get; set; }
}
public class SyslogSettings
{
/// <summary>
/// The connection string used to connect to a remote syslog server over TCP or UDP, or to connect locally.
/// </summary>
/// <remarks>
/// <para>The connection string will be parsed using <see cref="System.Uri" /> to extract the protocol, host name and port number.
/// </para>
/// <para>
/// Supported protocols are:
/// <list type="bullet">
/// <item>UDP (use <code>udp://</code>)</item>
/// <item>TCP (use <code>tcp://</code>)</item>
/// <item>TLS over TCP (use <code>tls://</code>)</item>
/// </list>
/// </para>
/// </remarks>
/// <example>
/// A remote server (logging.dev.example.com) is listening on UDP (port 514):
/// <code>
/// udp://logging.dev.example.com:514</code>.
/// </example>
public string Destination { get; set; }
/// <summary>
/// The absolute path to a Certificate (DER or Base64 encoded with private key).
/// </summary>
/// <remarks>
/// The certificate path and <see cref="CertificatePassword"/> are passed into the <see cref="System.Security.Cryptography.X509Certificates.X509Certificate2.X509Certificate2(string, string)" />.
/// The file format of the certificate may be binary encoded (DER) or base64. If the private key is encrypted, provide the password in <see cref="CertificatePassword"/>,
/// </remarks>
public string CertificatePath { get; set; }
/// <summary>
/// The password for the encrypted private key in the certificate supplied in <see cref="CertificatePath" />.
/// </summary>
/// <value></value>
public string CertificatePassword { get; set; }
/// <summary>
/// The thumbprint of the certificate in the X.509 certificate store for personal certificates for the user account running Bitwarden.
/// </summary>
/// <value></value>
public string CertificateThumbprint { get; set; }
}
public class NotificationHubSettings
{
private string _connectionString;

View File

@ -20,7 +20,6 @@ public interface IGlobalSettings
IConnectionStringSettings Storage { get; set; }
IBaseServiceUriSettings BaseServiceUri { get; set; }
ISsoSettings Sso { get; set; }
ILogLevelSettings MinLogLevel { get; set; }
IPasswordlessAuthSettings PasswordlessAuth { get; set; }
IDomainVerificationSettings DomainVerification { get; set; }
ILaunchDarklySettings LaunchDarkly { get; set; }

View File

@ -1,74 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings;
public interface ILogLevelSettings
{
IBillingLogLevelSettings BillingSettings { get; set; }
IApiLogLevelSettings ApiSettings { get; set; }
IIdentityLogLevelSettings IdentitySettings { get; set; }
IScimLogLevelSettings ScimSettings { get; set; }
ISsoLogLevelSettings SsoSettings { get; set; }
IAdminLogLevelSettings AdminSettings { get; set; }
IEventsLogLevelSettings EventsSettings { get; set; }
IEventsProcessorLogLevelSettings EventsProcessorSettings { get; set; }
IIconsLogLevelSettings IconsSettings { get; set; }
INotificationsLogLevelSettings NotificationsSettings { get; set; }
}
public interface IBillingLogLevelSettings
{
LogEventLevel Default { get; set; }
LogEventLevel Jobs { get; set; }
}
public interface IApiLogLevelSettings
{
LogEventLevel Default { get; set; }
LogEventLevel IdentityToken { get; set; }
LogEventLevel IpRateLimit { get; set; }
}
public interface IIdentityLogLevelSettings
{
LogEventLevel Default { get; set; }
LogEventLevel IdentityToken { get; set; }
LogEventLevel IpRateLimit { get; set; }
}
public interface IScimLogLevelSettings
{
LogEventLevel Default { get; set; }
}
public interface ISsoLogLevelSettings
{
LogEventLevel Default { get; set; }
}
public interface IAdminLogLevelSettings
{
LogEventLevel Default { get; set; }
}
public interface IEventsLogLevelSettings
{
LogEventLevel Default { get; set; }
LogEventLevel IdentityToken { get; set; }
}
public interface IEventsProcessorLogLevelSettings
{
LogEventLevel Default { get; set; }
}
public interface IIconsLogLevelSettings
{
LogEventLevel Default { get; set; }
}
public interface INotificationsLogLevelSettings
{
LogEventLevel Default { get; set; }
LogEventLevel IdentityToken { get; set; }
}

View File

@ -1,8 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings.LoggingSettings;
public class AdminLogLevelSettings : IAdminLogLevelSettings
{
public LogEventLevel Default { get; set; } = LogEventLevel.Error;
}

View File

@ -1,10 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings.LoggingSettings;
public class ApiLogLevelSettings : IApiLogLevelSettings
{
public LogEventLevel Default { get; set; } = LogEventLevel.Error;
public LogEventLevel IdentityToken { get; set; } = LogEventLevel.Fatal;
public LogEventLevel IpRateLimit { get; set; } = LogEventLevel.Information;
}

View File

@ -1,9 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings.LoggingSettings;
public class BillingLogLevelSettings : IBillingLogLevelSettings
{
public LogEventLevel Default { get; set; } = LogEventLevel.Warning;
public LogEventLevel Jobs { get; set; } = LogEventLevel.Information;
}

View File

@ -1,9 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings.LoggingSettings;
public class EventsLogLevelSettings : IEventsLogLevelSettings
{
public LogEventLevel Default { get; set; } = LogEventLevel.Error;
public LogEventLevel IdentityToken { get; set; } = LogEventLevel.Fatal;
}

View File

@ -1,8 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings.LoggingSettings;
public class EventsProcessorLogLevelSettings : IEventsProcessorLogLevelSettings
{
public LogEventLevel Default { get; set; } = LogEventLevel.Warning;
}

View File

@ -1,8 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings.LoggingSettings;
public class IconsLogLevelSettings : IIconsLogLevelSettings
{
public LogEventLevel Default { get; set; } = LogEventLevel.Error;
}

View File

@ -1,10 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings.LoggingSettings;
public class IdentityLogLevelSettings : IIdentityLogLevelSettings
{
public LogEventLevel Default { get; set; } = LogEventLevel.Error;
public LogEventLevel IdentityToken { get; set; } = LogEventLevel.Fatal;
public LogEventLevel IpRateLimit { get; set; } = LogEventLevel.Information;
}

View File

@ -1,16 +0,0 @@

namespace Bit.Core.Settings.LoggingSettings;
public class LogLevelSettings : ILogLevelSettings
{
public IBillingLogLevelSettings BillingSettings { get; set; } = new BillingLogLevelSettings();
public IApiLogLevelSettings ApiSettings { get; set; } = new ApiLogLevelSettings();
public IIdentityLogLevelSettings IdentitySettings { get; set; } = new IdentityLogLevelSettings();
public IScimLogLevelSettings ScimSettings { get; set; } = new ScimLogLevelSettings();
public ISsoLogLevelSettings SsoSettings { get; set; } = new SsoLogLevelSettings();
public IAdminLogLevelSettings AdminSettings { get; set; } = new AdminLogLevelSettings();
public IEventsLogLevelSettings EventsSettings { get; set; } = new EventsLogLevelSettings();
public IEventsProcessorLogLevelSettings EventsProcessorSettings { get; set; } = new EventsProcessorLogLevelSettings();
public IIconsLogLevelSettings IconsSettings { get; set; } = new IconsLogLevelSettings();
public INotificationsLogLevelSettings NotificationsSettings { get; set; } = new NotificationsLogLevelSettings();
}

View File

@ -1,9 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings.LoggingSettings;
public class NotificationsLogLevelSettings : INotificationsLogLevelSettings
{
public LogEventLevel Default { get; set; } = LogEventLevel.Warning;
public LogEventLevel IdentityToken { get; set; } = LogEventLevel.Fatal;
}

View File

@ -1,8 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings.LoggingSettings;
public class ScimLogLevelSettings : IScimLogLevelSettings
{
public LogEventLevel Default { get; set; } = LogEventLevel.Warning;
}

View File

@ -1,8 +0,0 @@
using Serilog.Events;
namespace Bit.Core.Settings.LoggingSettings;
public class SsoLogLevelSettings : ISsoLogLevelSettings
{
public LogEventLevel Default { get; set; } = LogEventLevel.Error;
}

View File

@ -1,165 +1,78 @@
using System.Security.Cryptography.X509Certificates;
using Bit.Core.Settings;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
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)
/// <summary>
///
/// </summary>
/// <param name="hostBuilder"></param>
/// <returns></returns>
public static IHostBuilder AddSerilogFileLogging(this IHostBuilder hostBuilder)
{
if (env.IsDevelopment() && !globalSettings.EnableDevLogging)
return hostBuilder.ConfigureLogging((context, logging) =>
{
return;
}
applicationLifetime.ApplicationStopped.Register(Log.CloseAndFlush);
}
public static ILoggingBuilder AddSerilog(
this ILoggingBuilder builder,
WebHostBuilderContext context,
Func<LogEvent, IGlobalSettings, bool>? 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)
if (context.HostingEnvironment.IsDevelopment())
{
return true;
return;
}
var eventId = e.Properties.TryGetValue("EventId", out var eventIdValue) ? eventIdValue.ToString() : null;
if (eventId?.Contains(Constants.BypassFiltersEventId.ToString()) ?? false)
// If they have begun using the new settings location, use that
if (!string.IsNullOrEmpty(context.Configuration["Logging:PathFormat"]))
{
return true;
}
return filter(e, globalSettings);
}
var logSentryWarning = false;
var logSyslogWarning = false;
// Path format is the only required option for file logging, we will use that as
// the keystone for if they have configured the new location.
var newPathFormat = context.Configuration["Logging:PathFormat"];
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))
{
logSyslogWarning = true;
// 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 (!string.IsNullOrEmpty(newPathFormat))
{
// Use new location
builder.AddFile(context.Configuration.GetSection("Logging"));
}
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);
logging.AddFile(context.Configuration.GetSection("Logging"));
}
else
{
var pathFormat = Path.Combine(globalSettings.LogDirectory, $"{globalSettings.ProjectName.ToLowerInvariant()}_{{Date}}.log");
if (globalSettings.LogDirectoryByProject)
var globalSettingsSection = context.Configuration.GetSection("GlobalSettings");
var loggingOptions = new LegacyFileLoggingOptions();
globalSettingsSection.Bind(loggingOptions);
if (string.IsNullOrWhiteSpace(loggingOptions.LogDirectory))
{
pathFormat = Path.Combine(globalSettings.LogDirectory, globalSettings.ProjectName, "{Date}.txt");
return;
}
var projectName = loggingOptions.ProjectName
?? context.HostingEnvironment.ApplicationName;
if (loggingOptions.LogRollBySizeLimit.HasValue)
{
var pathFormat = loggingOptions.LogDirectoryByProject
? Path.Combine(loggingOptions.LogDirectory, projectName, "log.txt")
: Path.Combine(loggingOptions.LogDirectory, $"{projectName.ToLowerInvariant()}.log");
logging.AddFile(
pathFormat: pathFormat,
fileSizeLimitBytes: loggingOptions.LogRollBySizeLimit.Value
);
}
else
{
var pathFormat = loggingOptions.LogDirectoryByProject
? Path.Combine(loggingOptions.LogDirectory, projectName, "{Date}.txt")
: Path.Combine(loggingOptions.LogDirectory, $"{projectName.ToLowerInvariant()}_{{Date}}.log");
logging.AddFile(
pathFormat: pathFormat
);
}
config.WriteTo.RollingFile(pathFormat);
}
config
.Enrich.FromLogContext()
.Enrich.WithProperty("Project", globalSettings.ProjectName);
}
});
}
var serilog = config.CreateLogger();
if (logSentryWarning)
{
serilog.Warning("Sentry for logging has been deprecated. Read more: https://btwrdn.com/log-deprecation");
}
if (logSyslogWarning)
{
serilog.Warning("Syslog for logging has been deprecated. Read more: https://btwrdn.com/log-deprecation");
}
builder.AddSerilog(serilog);
return builder;
/// <summary>
/// Our own proprietary options that we've always supported in `GlobalSettings` configuration section.
/// </summary>
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; }
}
}

View File

@ -12,26 +12,8 @@ public class Program
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureLogging((hostingContext, logging) =>
logging.AddSerilog(hostingContext, (e, globalSettings) =>
{
var context = e.Properties["SourceContext"].ToString();
if (context.Contains("Duende.IdentityServer.Validation.TokenValidator") ||
context.Contains("Duende.IdentityServer.Validation.TokenRequestValidator"))
{
return e.Level >= globalSettings.MinLogLevel.EventsSettings.IdentityToken;
}
if (e.Properties.TryGetValue("RequestPath", out var requestPath) &&
!string.IsNullOrWhiteSpace(requestPath?.ToString()) &&
(context.Contains(".Server.Kestrel") || context.Contains(".Core.IISHttpServer")))
{
return false;
}
return e.Level >= globalSettings.MinLogLevel.EventsSettings.Default;
}));
})
.AddSerilogFileLogging()
.Build()
.Run();
}

View File

@ -90,11 +90,8 @@ public class Startup
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IHostApplicationLifetime appLifetime,
GlobalSettings globalSettings)
{
app.UseSerilog(env, appLifetime, globalSettings);
// Add general security headers
app.UseMiddleware<SecurityHeadersMiddleware>();

View File

@ -14,9 +14,6 @@
"events": {
"connectionString": "SECRET"
},
"sentry": {
"dsn": "SECRET"
},
"amazon": {
"accessKeyId": "SECRET",
"accessKeySecret": "SECRET",

View File

@ -11,9 +11,8 @@ public class Program
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureLogging((hostingContext, logging) =>
logging.AddSerilog(hostingContext, (e, globalSettings) => e.Level >= globalSettings.MinLogLevel.EventsProcessorSettings.Default));
})
.AddSerilogFileLogging()
.Build()
.Run();
}

View File

@ -1,5 +1,4 @@
using System.Globalization;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Bit.SharedWeb.Utilities;
using Microsoft.IdentityModel.Logging;
@ -37,14 +36,9 @@ public class Startup
services.AddHostedService<AzureQueueHostedService>();
}
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IHostApplicationLifetime appLifetime,
GlobalSettings globalSettings)
public void Configure(IApplicationBuilder app)
{
IdentityModelEventSource.ShowPII = true;
app.UseSerilog(env, appLifetime, globalSettings);
// Add general security headers
app.UseMiddleware<SecurityHeadersMiddleware>();
app.UseRouting();

View File

@ -11,9 +11,8 @@ public class Program
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureLogging((hostingContext, logging) =>
logging.AddSerilog(hostingContext, (e, globalSettings) => e.Level >= globalSettings.MinLogLevel.IconsSettings.Default));
})
.AddSerilogFileLogging()
.Build()
.Run();
}

View File

@ -60,11 +60,8 @@ public class Startup
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IHostApplicationLifetime appLifetime,
GlobalSettings globalSettings)
{
app.UseSerilog(env, appLifetime, globalSettings);
// Add general security headers
app.UseMiddleware<SecurityHeadersMiddleware>();

View File

@ -1,8 +1,4 @@
// FIXME: Update this file to be null safe and then delete the line below
#nullable disable
using AspNetCoreRateLimit;
using Bit.Core.Utilities;
using Bit.Core.Utilities;
namespace Bit.Identity;
@ -23,23 +19,7 @@ public class Program
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureLogging((hostingContext, logging) =>
logging.AddSerilog(hostingContext, (e, globalSettings) =>
{
var context = e.Properties["SourceContext"].ToString();
if (context.Contains(typeof(IpRateLimitMiddleware).FullName))
{
return e.Level >= globalSettings.MinLogLevel.IdentitySettings.IpRateLimit;
}
if (context.Contains("Duende.IdentityServer.Validation.TokenValidator") ||
context.Contains("Duende.IdentityServer.Validation.TokenRequestValidator"))
{
return e.Level >= globalSettings.MinLogLevel.IdentitySettings.IdentityToken;
}
return e.Level >= globalSettings.MinLogLevel.IdentitySettings.Default;
}));
});
})
.AddSerilogFileLogging();
}
}

View File

@ -170,14 +170,11 @@ public class Startup
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IHostApplicationLifetime appLifetime,
GlobalSettings globalSettings,
ILogger<Startup> logger)
{
IdentityModelEventSource.ShowPII = true;
app.UseSerilog(env, appLifetime, globalSettings);
// Add general security headers
app.UseMiddleware<SecurityHeadersMiddleware>();

View File

@ -27,9 +27,6 @@
"events": {
"connectionString": "SECRET"
},
"sentry": {
"dsn": "SECRET"
},
"notificationHub": {
"connectionString": "SECRET",
"hubName": "SECRET"

View File

@ -1,5 +1,4 @@
using Bit.Core.Utilities;
using Serilog.Events;
namespace Bit.Notifications;
@ -13,37 +12,8 @@ public class Program
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureLogging((hostingContext, logging) =>
logging.AddSerilog(hostingContext, (e, globalSettings) =>
{
var context = e.Properties["SourceContext"].ToString();
if (context.Contains("Duende.IdentityServer.Validation.TokenValidator") ||
context.Contains("Duende.IdentityServer.Validation.TokenRequestValidator"))
{
return e.Level >= globalSettings.MinLogLevel.NotificationsSettings.IdentityToken;
}
if (e.Level == LogEventLevel.Error &&
e.MessageTemplate.Text == "Failed connection handshake.")
{
return false;
}
if (e.Level == LogEventLevel.Error &&
e.MessageTemplate.Text.StartsWith("Failed writing message."))
{
return false;
}
if (e.Level == LogEventLevel.Warning &&
e.MessageTemplate.Text.StartsWith("Heartbeat took longer"))
{
return false;
}
return e.Level >= globalSettings.MinLogLevel.NotificationsSettings.Default;
}));
})
.AddSerilogFileLogging()
.Build()
.Run();
}

View File

@ -82,11 +82,9 @@ public class Startup
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IHostApplicationLifetime appLifetime,
GlobalSettings globalSettings)
{
IdentityModelEventSource.ShowPII = true;
app.UseSerilog(env, appLifetime, globalSettings);
// Add general security headers
app.UseMiddleware<SecurityHeadersMiddleware>();

View File

@ -18,9 +18,6 @@
"connectionString": "SECRET",
"applicationCacheTopicName": "SECRET"
},
"sentry": {
"dsn": "SECRET"
},
"amazon": {
"accessKeyId": "SECRET",
"accessKeySecret": "SECRET",

View File

@ -1,13 +1,9 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Hosting;
using Bit.Core.Utilities;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Serilog;
using Serilog.Extensions.Logging;
using Xunit;
@ -23,18 +19,6 @@ public class LoggerFactoryExtensionsTests
Assert.Empty(providers);
}
[Fact]
public void AddSerilog_IsDevelopment_DevLoggingEnabled_AddsSerilog()
{
var providers = GetProviders(new Dictionary<string, string?>
{
{ "GlobalSettings:EnableDevLogging", "true" },
}, "Development");
var provider = Assert.Single(providers);
Assert.IsAssignableFrom<SerilogLoggerProvider>(provider);
}
[Fact]
public void AddSerilog_IsProduction_AddsSerilog()
{
@ -52,7 +36,7 @@ public class LoggerFactoryExtensionsTests
var providers = GetProviders(new Dictionary<string, string?>
{
{ "GlobalSettings:ProjectName", "Test" },
{ "GlobalSetting:LogDirectoryByProject", "true" },
{ "GlobalSettings:LogDirectoryByProject", "true" },
{ "GlobalSettings:LogDirectory", tempDir.FullName },
});
@ -62,6 +46,8 @@ public class LoggerFactoryExtensionsTests
var logger = provider.CreateLogger("Test");
logger.LogWarning("This is a test");
provider.Dispose();
var logFile = Assert.Single(tempDir.EnumerateFiles("Test/*.txt"));
var logFileContents = await File.ReadAllTextAsync(logFile.FullName);
@ -104,62 +90,6 @@ public class LoggerFactoryExtensionsTests
logFileContents
);
}
[Fact(Skip = "Only for local development.")]
public async Task AddSerilog_SyslogConfigured_Warns()
{
// Setup a fake syslog server
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
using var listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 25000);
listener.Start();
var provider = GetServiceProvider(new Dictionary<string, string?>
{
{ "GlobalSettings:SysLog:Destination", "tcp://127.0.0.1:25000" },
{ "GlobalSettings:SiteName", "TestSite" },
{ "GlobalSettings:ProjectName", "TestProject" },
}, "Production");
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Test");
logger.LogWarning("This is a test");
// Look in syslog for data
using var socket = await listener.AcceptSocketAsync(cts.Token);
// This is rather lazy as opposed to implementing smarter syslog message
// reading but thats not what this test about, so instead just give
// the sink time to finish its work in the background
List<string> messages = [];
while (true)
{
var buffer = new byte[1024];
var received = await socket.ReceiveAsync(buffer, SocketFlags.None, cts.Token);
if (received == 0)
{
break;
}
var response = Encoding.ASCII.GetString(buffer, 0, received);
messages.Add(response);
if (messages.Count == 2)
{
break;
}
}
Assert.Collection(
messages,
(firstMessage) => Assert.Contains("Syslog for logging has been deprecated", firstMessage),
(secondMessage) => Assert.Contains("This is a test", secondMessage)
);
}
private static IEnumerable<ILoggerProvider> GetProviders(Dictionary<string, string?> initialData, string environment = "Production")
{
var provider = GetServiceProvider(initialData, environment);
@ -172,23 +102,34 @@ public class LoggerFactoryExtensionsTests
.AddInMemoryCollection(initialData)
.Build();
var hostingEnvironment = Substitute.For<IWebHostEnvironment>();
var hostingEnvironment = Substitute.For<IHostEnvironment>();
hostingEnvironment
.EnvironmentName
.Returns(environment);
var context = new WebHostBuilderContext
var context = new HostBuilderContext(new Dictionary<object, object>())
{
HostingEnvironment = hostingEnvironment,
Configuration = config,
};
var services = new ServiceCollection();
services.AddLogging(builder =>
{
builder.AddSerilog(context);
});
var hostBuilder = Substitute.For<IHostBuilder>();
hostBuilder
.When(h => h.ConfigureServices(Arg.Any<Action<HostBuilderContext, IServiceCollection>>()))
.Do(call =>
{
var configureAction = call.Arg<Action<HostBuilderContext, IServiceCollection>>();
configureAction(context, services);
});
hostBuilder.AddSerilogFileLogging();
hostBuilder
.ConfigureServices(Arg.Any<Action<HostBuilderContext, IServiceCollection>>())
.Received(1);
return services.BuildServiceProvider();
}