【问题标题】:In Serilog dynamically changing log file path?在 Serilog 中动态更改日志文件路径?
【发布时间】:2020-05-19 11:18:42
【问题描述】:

我具有动态更改日志文件路径的功能。但是当我更改在 Consul 中可配置的路径时,它会在两个地方(即旧路径和新路径)写入部分日志。更改日志文件路径应该可以在没有任何服务重新启动的情况下工作。我们如何存档?

我们在日志文件中写如下:

.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 的可配置路径。当我们更改路径时,它会在新路径上创建一个日志文件,但同时也会继续写入旧路径文件。

所以我们希望它停止写入旧路径。

【问题讨论】:

    标签: serilog


    【解决方案1】:

    您可以尝试使用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();
    

    【讨论】:

    • Wrt .Enrich.With&lt;LogFileNameEnricher&gt;(),当我尝试实施时出现以下错误:CS1503 cannot convert from 'SomeProgramNamespace.LogFileNameEnricher' to 'Serilog.Core.ILogEventEnricher',有什么想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多