不能为 serilog 配置自定义接收器
Сan't configure a custom sink for a serilog
我无法通过配置文件将自定义接收器连接到记录器。我在 .Net 5 和 .Net Core 3.1 下试过。
我也看到了对相同请求的回复。
但出于某种原因,这对我不起作用。
为了重现这个问题,我制作了一个简约的应用程序。也不起作用,就像在我的主要项目中一样。
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();
我无法通过配置文件将自定义接收器连接到记录器。我在 .Net 5 和 .Net Core 3.1 下试过。
我也看到了对相同请求的回复。
但出于某种原因,这对我不起作用。
为了重现这个问题,我制作了一个简约的应用程序。也不起作用,就像在我的主要项目中一样。
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();