Serilog - 覆盖配置值

4
我正在开发一个Windows 10应用程序(UWP),并使用Serilog实现日志记录。
下面是一个appsettings.json文件,我在其中配置Serilog以写入滚动文件池(以及其他池)。
{
  "Serilog": {
    "Using": [ "Serilog.Sinks.Console" ],
    "MinimumLevel": "Debug",
    "WriteTo": [
      { "Name": "Console" },
      {
        "Name": "RollingFile",
        "Args": {
          "pathFormat": "#{LogFilePath}log-{Date}.txt",
          "fileSizeLimitBytes": "3000",
          "retainedFileCountLimit": "2"
        }
      }      
    ],
    "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
    "Properties": {
      "Application": "Sample"
    }
  }
}

我随后调用以下代码:

 var configuration = new ConfigurationBuilder()                        
        .AddJsonFile(sampleFile.Path)
        .Build();

    Log.Logger = new LoggerConfiguration()
        .ReadFrom.Configuration(configuration)
        .CreateLogger();

然而,我需要在运行时能够更改pathFormat属性,以便将日志写入应用程序的“LocalState”文件夹。
问:Serilog是否支持从配置中读取,然后在运行时覆盖特定参数?
我的当前解决方法是在JSON中使用一个名为“#{LogFilePath}”的令牌,并在运行时替换该文件。
我找到了以下内容,但在我的情况下无法使用环境变量:指定Serilog滚动文件路径的目录
2个回答

5

根据Serilog的说法, 您需要使用文件记录日志 - 看起来,RollingFile可能很快就会消失。

重要提示:此汇流功能已改进并合并到Serilog.Sinks.File软件包中。 RollingFile将在可预见的未来得到维护,但对于新应用程序,建议使用File。

固定格式

这是使用文件汇流器的简单方法:

appsettings.json

{
  "Serilog": {
    "MinimumLevel": "Verbose",
    "WriteTo": [
      {
        "Name": "Console"        
      },
      {
        "Name": "File",
        "Args": {
          "path": "Logs\\log.txt",
          "fileSizeLimitBytes": 3000,
          "buffered": false,
          "rollOnFileSizeLimit": true,
          "retainedFileCountLimit": 3,
          "rollingInterval": "Hour"
        }
      }
    ]
  }
}

Program.cs

var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).Build();
var loggerConfig = new LoggerConfiguration().ReadFrom.Configuration(configuration);
var logger = loggerConfig.CreateLogger();

自定义格式

去年,Serilog团队和社区似乎有一些热情来指定一些默认配置,然后通过配置文件进行覆盖。他们创建了一个实验性仓库和一个Nuget包 - 不确定今天的情况如何。

但我认为有一个解决方法 - 下面是一种比您的“token”方法更清洁的实现方式之一。

appsettings.json

{
  "FileLogger": {
    //"path": "Logs\\log.txt",
  }
}

如果您在配置文件中指定了值,则会优先使用该值。否则,将使用您的自定义格式。在我的观点中,首先在应用程序中指定默认值,然后使用配置来覆盖它们(而不是相反)是更好的设计。

Program.cs

var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).Build();

var customLogFileFormat = configuration["FileLogger:path"] ?? $"Logs\\log_{DateTime.Now.ToString("MMddyyyy_hhmmsstt")}log.txt";

var loggerConfig = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .WriteTo.Console()
                .WriteTo.File(
                    path: customLogFileFormat,
                    fileSizeLimitBytes: 3000,
                    buffered: true,
                    rollOnFileSizeLimit: true,
                    rollingInterval: RollingInterval.Day,
                    retainedFileCountLimit: 5);

如果您对我的测试应用程序有更多的细节感兴趣,以下一系列的PoweShell命令可能会有所帮助:

mkdir SerilogApp
cd SerilogApp
dotnet new console -f netcoreapp2.2 -n SerilogApp -o SerilogApp
dotnet new sln -n SerilogApp.sln
dotnet sln add .\SerilogApp\SerilogApp.csproj
dotnet add .\SerilogApp\SerilogApp.csproj package Microsoft.Extensions.Configuration -f netcoreapp2.2
dotnet add .\SerilogApp\SerilogApp.csproj package Microsoft.Extensions.Configuration.FileExtensions -f netcoreapp2.2
dotnet add .\SerilogApp\SerilogApp.csproj package Microsoft.Extensions.Configuration.Json -f netcoreapp2.2
dotnet add .\SerilogApp\SerilogApp.csproj package Serilog -f netcoreapp2.2
dotnet add .\SerilogApp\SerilogApp.csproj package Serilog.Settings.Configuration -f netcoreapp2.2
dotnet add .\SerilogApp\SerilogApp.csproj package Serilog.Sinks.Console -f netcoreapp2.2
 dotnet add .\SerilogApp\SerilogApp.csproj package Serilog.Sinks.File -f netcoreapp2.2 -v 4.0.0
cd .\SerilogApp
echo $null >> appsettings.json

1
我将这个答案保持得比较基础。如果你正在使用 DI,这篇文章可能会有所帮助 https://stackoverflow.com/q/55551654/799593。 - ablaze
嗨@ablaze。感谢提供的信息。看起来Serilog不支持这个功能,需要修改从配置文件中读取的值?如果是这样,我宁愿创建自己的config.settings,读取并在代码中配置Serilog。 - Howard
@Howard,是的,你可以利用项目模板中任何现有的.config或.json设置文件,也可以创建一个单独的文件并在主配置中引用它——这有助于“关注点分离”,特别是对于大型项目。如果我的回答解决了你的问题,请考虑将其标记为其他人的答案,并选择性地点赞。谢谢! - ablaze
3
但是 Serilog 是否有一种自动初始化的方式,基于 appsettings.json 但在 Startup.cs 中通过代码重写某些设置? - BaltoStar

3
您可以在从JSON读取配置后,在使用它创建记录器之前更改配置。假设以下JSON:
{
  "Serilog": {
    "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
    "MinimumLevel": {
      "Default": "Debug"
    },
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"
        }
      },
      {
        "Name": "File",
        "Args": {
          "path": "placeholder",
          "buffered": false,
          "outputTemplate": "[{Timestamp:HH:mm:ss.fff} {Level:u3}] {Message}{NewLine}{Exception}",
          "rollingInterval": "Day"
        }
      }
    ],
    "Enrich": [ "FromLogContext" ]
  }
}

在调用CreateLogger之前,使用以下代码将json文件中的“占位符”更新为“abc.log”。

 var configuration = new ConfigurationBuilder()
         .AddJsonFile(AppSettingsPath, 
             optional: false, reloadOnChange: true)
         .Build();

 configuration["Serilog:WriteTo:1:Args:path"] = "abc.log";

 Log.Logger = new LoggerConfiguration()
     .ReadFrom.Configuration(configuration)
     .WriteTo.SerilogSink(MessageBroker.Broker)
     .CreateLogger();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接