我有动态改变日志文件路径的特性。但是当我更改在领事中可配置的路径时,它会在两处写入部分日志,即在旧路径上以及在新路径上。更改日志文件路径应在不重新启动任何服务的情况下工作。我们怎么才能把它存档?
我们正在日志文件中写入以下内容:
.WriteTo.File(logFolderFullPath + "\\" + applicationName + "_.txt",
LogEventLevel.Error, shared: true,
fileSizeLimitBytes: fileSizeLimitBytes, rollOnFileSizeLimit: true, rollingInterval: RollingInterval.Day,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] [{MachineName}] [{SourceContext}] {RequestId} {CorrelationId} {Message}{NewLine}{Exception}{properties}")
logFolderFullPath
是来自appsetting.json
的可配置路径。当我们更改路径时,它会在新路径上创建日志文件,但同时也会继续在旧路径文件中写入日志文件。
所以我们希望它不要再写旧的路了。
发布于 2020-05-28 22:57:05
您可以尝试使用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();
在您的示例中,您希望根据对配置的更改动态更改此属性名称。这样做的一个简单方法是创建一个自定义浓缩剂,它可以根据您的配置设置更改属性的值,如上面的值。
您的自定义浓缩剂应该如下所示:
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);
}
}
注意:如果您使用期权模式,而不是每次写入日志消息时检查配置,上面的示例会更有效。
使用可以根据配置动态为您设置LogFilePath
属性的充实器,您只需配置日志管道以基于该属性映射即可。
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.With<LogFileNameEnricher>()
.WriteTo.Map(LogFileNameEnricher.LogFilePathPropertyName,
(logFilePath, wt) => wt.File($"{logFilePath}"), sinkMapCountLimit: 1)
.CreateLogger();
// ...
Log.CloseAndFlush();
发布于 2022-08-28 00:04:27
Serilog FileSink不允许在设置路径后修改路径。我仍然倾向于使用appsettings.json来存储serilog配置,但我在使用它之前对配置进行了黑客攻击。
我的appsettings.json看起来是这样的:
...
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "../logs/log-.txt",
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
"rollingInterval": "Day",
"buffered": true
}
}
]
...
在配置Serilog之前,我已经创建了一个扩展方法来覆盖来自appsettings.json的配置。
public static class IHostBuilderExtensions
{
public static IHostBuilder ConfigureSerilog(this IHostBuilder hostBuilder, string appName)
{
return hostBuilder.ConfigureAppConfiguration((hostCtx, configBuilder) =>
{
var config = configBuilder.Build();
var pid = Process.GetCurrentProcess().Id;
var logFilePath = $@"{MyLogFolder}\\{appName}_pid_{pid}_.txt";
var logFileNameWithPidPattern = $"{appName}_pid_{pid}_.txt";
const string serilogWriteConfigPattern = "Serilog:WriteTo:";
const string serilogFilePathConfigPattern = ":Args:path";
var serilogFoundKvpFilePathFromConfig = config
.AsEnumerable()
.FirstOrDefault(kvp =>
kvp.Key.Contains(serilogWriteConfigPattern, StringComparison.InvariantCultureIgnoreCase)
&& kvp.Key.Contains(serilogFilePathConfigPattern, StringComparison.InvariantCultureIgnoreCase))
;
var keyToReplace = serilogFoundKvpFilePathFromConfig.Key;
var overridenValue = serilogFoundKvpFilePathFromConfig.Value
.Replace("log-.txt", logFileNameWithPidPattern);
var serilogWriteToFilePathOverride = KeyValuePair.Create(keyToReplace, overridenValue);
configBuilder.AddInMemoryCollection(new[] { serilogWriteToFilePathOverride });
})
.UseSerilog((ctx, lc) =>
{
lc
// At this point, the config has been updated
// and the file name contains the Process Id:
// eg.: MyName_pid_15940_20220826.txt
.ReadFrom.Configuration(ctx.Configuration)
.WriteTo
.Console();
});
}
}
我在Program.cs中使用它的方式如下:
...
hostBuilder
.ConfigureAppConfiguration((hostCtx, configBuilder) => { /* other config */ })
.ConfigureSerilog(appName)
...
https://stackoverflow.com/questions/61889762
复制相似问题