您可以尝试使用Serilog.Settings.Reloader,它可以在您的配置更改时在运行时交换您的记录器实例。
另一种在运行时更改记录器属性的常用方法是使用Serilog.Sinks.Map,这是一个基于日志事件属性调度事件的接收器。
下面的示例使用名为FileName 的日志事件属性来决定它将写入的日志文件的名称,因此每当此属性更改时,日志文件都会相应更改:
Log.Logger = new LoggerConfiguration()
.WriteTo.Map("FileName", "IDontKnow", (fileName, wt) => wt.File($"{fileName}.txt"))
.CreateLogger();
Log.ForContext("FileName", "Alice").Information("Hey!"); // writes to Alice.txt
Log.ForContext("FileName", "Bob").Information("Hello!"); // writes to Bob.txt
Log.Information("Hi Again!"); // writes to IDontKnow.txt (default if property is missing)
Log.CloseAndFlush();
在您的情况下,您希望根据对配置的更改动态更改此属性名称。一种简单的方法是创建一个自定义enricher,它可以根据您的配置设置更改上述属性的值。
您的自定义 enricher 看起来像这样:
internal class LogFilePathEnricher : ILogEventEnricher
{
private string _cachedLogFilePath;
private LogEventProperty _cachedLogFilePathProperty;
public const string LogFilePathPropertyName = "LogFilePath";
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
var logFilePath = // Read path from your appsettings.json
// Check for null, etc...
LogEventProperty logFilePathProperty;
if (logFilePath.Equals(_cachedLogFilePath))
{
// Path hasn't changed, so let's use the cached property
logFilePathProperty = _cachedLogFilePathProperty;
}
else
{
// We've got a new path for the log. Let's create a new property
// and cache it for future log events to use
_cachedLogFilePath = logFilePath;
_cachedLogFilePathProperty = logFilePathProperty =
propertyFactory.CreateProperty(LogFilePathPropertyName, logFilePath);
}
logEvent.AddPropertyIfAbsent(logFilePathProperty);
}
}
注意:如果您使用Options pattern,而不是每次写入日志消息时检查配置,上面的示例丰富器可能会更有效。
使用可以根据配置为您动态设置 LogFilePath 属性的丰富器,您只需配置日志管道以基于该属性进行映射。
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.With<LogFileNameEnricher>()
.WriteTo.Map(LogFileNameEnricher.LogFilePathPropertyName,
(logFilePath, wt) => wt.File($"{logFilePath}"), sinkMapCountLimit: 1)
.CreateLogger();
// ...
Log.CloseAndFlush();