Reputation: 117
I can't connect the custom sink to the logger via the configuration file. I tried under .Net 5 and .Net Core 3.1.
I studied the documentation: https://github.com/serilog/serilog-settings-configuration#using-section-and-auto-discovery-of-configuration-assemblies
I also saw responses to an identical request. https://stackoverflow.com/a/50118486/13151982 https://stackoverflow.com/a/24922105/13151982
But for some reason, this does not work for me.
To reproduce the problem, I made a minimalistic application. Also does not work, as in my main project.
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>
Simple custom sink:
public class SerilogCounterSink : ILogEventSink
{
private static int i = 0;
public void Emit(LogEvent logEvent)
{
i++;
}
}
Configuration:
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();
Configuration via file:
"Serilog": {
"Using": [ "SampleApp" ],
"WriteTo": [
{ "Name": "SerilogCounterSink" },
{ "Name": "Console" },
{
"Name": "File",
"Args": { "path": "Logs/log.txt" }
}
],
"MinimalLevel": {
"Default": "Information",
"Override": {
"System": "Warning",
"Microsoft": "Information"
}
}
}
I tried like this:
"WriteTo": [
{ "Name": "SampleApp.SerilogCounterSink" },
"WriteTo": [
{ "Name": "SerilogCounter" },
"WriteTo": [
{ "Name": "SampleApp.SerilogCounter" },
As a result, when writing
_log.LogInformation("test");
I do not get into the SerilogCounterSink.Emit (put a breakpoint there). If i uncomment a line of code where a custom sink is added programmatically, then everything works - I get into the method.
Upvotes: 3
Views: 4153
Reputation: 27848
The Serilog configuration extension doesn't create instances of the sinks directly. All it does is to try to call a method .WriteTo.NameOfTheSinkYouDefinedInTheConfig()
, if that exists - so for that to work, you need to provide this method yourself.
If you look at the source code of any of the official sinks, you'll notice that they are always declared as internal
classes rather than public
classes, and the way to hook sinks into the Serilog configuration is by creating an extension method to the LoggerSinkConfiguration
class where you instantiate the sink yourself and add it to the pipeline.
In your case, it would be something like this:
public static class SerilogCounterLoggerConfigurationExtensions
{
public static LoggerConfiguration SerilogCounterSink(
this LoggerSinkConfiguration sinkConfiguration)
{
return sinkConfiguration.Sink(new SerilogCounterSink(), LevelAlias.Minimum,
levelSwitch: null);
}
}
Now that the extension method is available, the configuration extension will be able to call it the same way you would do in code:
Log.Logger = new LoggerConfiguration()
.WriteTo.SerilogCounterSink() // <<<<<<<<<<<<<<
.CreateLogger();
Upvotes: 4