首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Serilog中动态更改日志文件路径?

在Serilog中动态更改日志文件路径?
EN

Stack Overflow用户
提问于 2020-05-19 11:18:42
回答 2查看 5.7K关注 0票数 3

我有动态改变日志文件路径的特性。但是当我更改在领事中可配置的路径时,它会在两处写入部分日志,即在旧路径上以及在新路径上。更改日志文件路径应在不重新启动任何服务的情况下工作。我们怎么才能把它存档?

我们正在日志文件中写入以下内容:

代码语言:javascript
运行
复制
.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的可配置路径。当我们更改路径时,它会在新路径上创建日志文件,但同时也会继续在旧路径文件中写入日志文件。

所以我们希望它不要再写旧的路了。

EN

回答 2

Stack Overflow用户

发布于 2020-05-28 22:57:05

您可以尝试使用Serilog.Settings.Reloader,它可以在配置更改时在运行时交换记录器实例。

另一种在运行时更改记录器属性的常见方法是使用Serilog.Sinks.Map,一种基于日志事件属性分派事件的接收器。

下面的示例使用名为FileName的日志事件属性来决定它将要写入的日志文件的名称,因此每当该属性发生更改时,日志文件就会相应更改:

代码语言:javascript
运行
复制
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();

在您的示例中,您希望根据对配置的更改动态更改此属性名称。这样做的一个简单方法是创建一个自定义浓缩剂,它可以根据您的配置设置更改属性的值,如上面的值。

您的自定义浓缩剂应该如下所示:

代码语言:javascript
运行
复制
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属性的充实器,您只需配置日志管道以基于该属性映射即可。

代码语言:javascript
运行
复制
Log.Logger = new LoggerConfiguration()
    .Enrich.FromLogContext()
    .Enrich.With<LogFileNameEnricher>()
    .WriteTo.Map(LogFileNameEnricher.LogFilePathPropertyName,
        (logFilePath, wt) => wt.File($"{logFilePath}"), sinkMapCountLimit: 1)
    .CreateLogger();

// ...

Log.CloseAndFlush();
票数 4
EN

Stack Overflow用户

发布于 2022-08-28 00:04:27

Serilog FileSink不允许在设置路径后修改路径。我仍然倾向于使用appsettings.json来存储serilog配置,但我在使用它之前对配置进行了黑客攻击。

我的appsettings.json看起来是这样的:

代码语言:javascript
运行
复制
...
        "WriteTo": [
            {
                "Name": "File",
                "Args": {
                    "path": "../logs/log-.txt",
                    "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
                    "rollingInterval": "Day",
                    "buffered": true
                }
            }
        ]
...

在配置Serilog之前,我已经创建了一个扩展方法来覆盖来自appsettings.json的配置。

代码语言:javascript
运行
复制
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中使用它的方式如下:

代码语言:javascript
运行
复制
...
 hostBuilder
  .ConfigureAppConfiguration((hostCtx, configBuilder) => { /* other config */ })
  .ConfigureSerilog(appName)
...
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61889762

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档