如何基于Serilog和ILogger动态切换日志数据库连接字符串
动态修改Serilog数据库连接字符串
我需要为Serilog动态修改数据库连接字符串。
现有配置代码
StartUp.cs中的Serilog配置
public void ConfigureServices(IServiceCollection services) { var cm = new ConnectionManager(config); Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(config) .Enrich.FromLogContext() .WriteTo.MSSqlServer( cm.GetConnectionString(cm.GetPropertyFromConfig("Serilog", "ConnectionName")), sinkOptions: new MSSqlServerSinkOptions { TableName = cm.GetPropertyFromConfig("Serilog", "TableName"), SchemaName = cm.GetPropertyFromConfig("Serilog", "SchemaName") }) .CreateLogger(); services.AddLogging(s => { s.ClearProviders(); s.AddSerilog(Log.Logger, dispose: true); }); services.AddTransient(provider => { var loggerFactory = provider.GetRequiredService<ILoggerFactory>(); const string categoryName = "Any"; return loggerFactory.CreateLogger(categoryName); }); }
ChangeConnection.cs的初始代码
public class ChangeConnection { private readonly ILogger _logger; public ChangeConnection(ILogger logger){ _logger = logger; } public void SwapConnection(string connectionString) { // 修改日志记录器的连接字符串,使后续日志写入新数据库 } }
调用代码示例
_logger.LogInformation("Logging to Current Database"); _changeConnection.SwapConnection("new connection string"); _logger.LogInformation("Logging to New Database");
解决方案
Serilog的Sink实例是不可变的,无法直接修改现有Sink的连接字符串,需要重新创建Logger并替换全局实例,同时更新DI中的日志服务。
修改ChangeConnection.cs
public class ChangeConnection { private readonly IConfiguration _config; private readonly ILoggerFactory _loggerFactory; // 注入配置和日志工厂,而非直接注入ILogger public ChangeConnection(IConfiguration config, ILoggerFactory loggerFactory) { _config = config; _loggerFactory = loggerFactory; } public void SwapConnection(string connectionString) { // 先关闭并刷新旧Logger,确保日志全部写入并释放资源 var oldLogger = Log.Logger; Log.CloseAndFlush(); // 基于新连接字符串创建新Logger var cm = new ConnectionManager(_config); var newLogger = new LoggerConfiguration() .ReadFrom.Configuration(_config) .Enrich.FromLogContext() .WriteTo.MSSqlServer( connectionString, sinkOptions: new MSSqlServerSinkOptions { TableName = cm.GetPropertyFromConfig("Serilog", "TableName"), SchemaName = cm.GetPropertyFromConfig("Serilog", "SchemaName") }) .CreateLogger(); // 更新全局Logger实例 Log.Logger = newLogger; // 更新日志工厂中的Serilog提供器,确保后续创建的ILogger使用新Logger var existingProvider = _loggerFactory.Services.OfType<SerilogLoggerProvider>().FirstOrDefault(); if (existingProvider != null) { _loggerFactory.RemoveProvider(existingProvider); _loggerFactory.AddSerilog(newLogger, dispose: true); } } }
注意事项
- 调用
Log.CloseAndFlush()是关键,避免旧Logger占用数据库连接或丢失未写入的日志。 - 需要在DI容器中注册
ChangeConnection,确保注入的IConfiguration和ILoggerFactory可用。 - 如果原配置中有多个Sink,重新创建Logger时要确保所有需要的Sink都被正确配置。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

