不能为 serilog 配置自定义接收器

Сan't configure a custom sink for a serilog

我无法通过配置文件将自定义接收器连接到记录器。我在 .Net 5 和 .Net Core 3.1 下试过。

我研究了文档: https://github.com/serilog/serilog-settings-configuration#using-section-and-auto-discovery-of-configuration-assemblies

我也看到了对相同请求的回复。

但出于某种原因,这对我不起作用。

为了重现这个问题,我制作了一个简约的应用程序。也不起作用,就像在我的主要项目中一样。

SampleApp.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
    <PackageReference Include="Serilog.Extensions.Hosting" Version="4.1.2" />
    <PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
    <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
  </ItemGroup>

  <ItemGroup>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

</Project>

简单的自定义水槽:

    public class SerilogCounterSink : ILogEventSink
    {
        private static int i = 0;

        public void Emit(LogEvent logEvent)
        {
            i++;
        }
    }

配置:

var builder = new ConfigurationBuilder();
            ConfigSetup(builder);

            // defining Serilog configs
            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(builder.Build())
                .Enrich.FromLogContext()
                .WriteTo.Console()
                //.WriteTo.Sink(new SerilogCounterSink())  //works if uncomment this line
                .CreateLogger();
            
            // Initiated the denpendency injection container 
            var host = Host.CreateDefaultBuilder()
                        .ConfigureServices((context, services) => {
                            services.AddTransient<IDataService, DataService>();
                        })
                        .UseSerilog()
                        .Build();

通过文件配置:

"Serilog": {
    "Using": [ "SampleApp" ],
    "WriteTo": [
      { "Name": "SerilogCounterSink" },
      { "Name": "Console" },
      {
        "Name": "File",
        "Args": { "path": "Logs/log.txt" }
      }
    ],
    "MinimalLevel": {
      "Default": "Information",
      "Override": {
        "System": "Warning",
        "Microsoft": "Information"
      }
    }
  }

我这样试过:

    "WriteTo": [
      { "Name": "SampleApp.SerilogCounterSink" },

    "WriteTo": [
      { "Name": "SerilogCounter" },

    "WriteTo": [
      { "Name": "SampleApp.SerilogCounter" },

结果,写的时候

_log.LogInformation("test");

我没有进入SerilogCounterSink.Emit(在那里放一个断点)。如果我取消注释以编程方式添加自定义接收器的代码行,那么一切正常 - 我进入该方法。

Serilog 配置扩展不会直接创建接收器的实例。它所做的只是尝试调用一个方法 .WriteTo.NameOfTheSinkYouDefinedInTheConfig(),如果该方法存在 - 所以要使其工作,您需要自己提供此方法。

如果你查看任何官方接收器的源代码,你会注意到它们总是被声明为 internal classes 而不是 public classes,将接收器挂接到 Serilog 配置的方法是通过创建 LoggerSinkConfiguration class 的扩展方法,您可以在其中实例化接收器并将其添加到管道中。

在你的情况下,它会是这样的:

public static class SerilogCounterLoggerConfigurationExtensions
{
    public static LoggerConfiguration SerilogCounterSink(
        this LoggerSinkConfiguration sinkConfiguration)
    {
        return sinkConfiguration.Sink(new SerilogCounterSink(), LevelAlias.Minimum,
            levelSwitch: null);
    }
}

现在扩展方法可用了,配置扩展将能够像在代码中那样调用它:

Log.Logger = new LoggerConfiguration()
    .WriteTo.SerilogCounterSink() // <<<<<<<<<<<<<<
    .CreateLogger();