I follow this article. Developing a sink
But I need to injection IHttpClientFactory.
public class MySink : ILogEventSink
{
//...
public MySink(IFormatProvider formatProvider, IHttpClientFactory httpClientFactory)
{
//...
}
}
public static class MySinkExtensions
{
public static LoggerConfiguration MySink(
this LoggerSinkConfiguration loggerConfiguration,
IHttpClientFactory httpClientFactory,
IFormatProvider formatProvider = null,
LogEventLevel restrictedToMinimumLevel = LogEventLevel.Verbose)
{
return loggerConfiguration.Sink(new MySink(formatProvider, httpClientFactory), restrictedToMinimumLevel);
}
}
Program Main:
class Program
{
static async Task Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddHttpClient();
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.WriteTo.MySink(null) //<--How to get IHttpClientFactory?
.CreateLogger();
services.AddLogging(configure => configure.ClearProviders().AddSerilog(logger));
var serviceProvider = services.BuildServiceProvider();
}
}
appsettings:
{
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "MyTestProject" ],
"WriteTo": [
{
"Name": "Console",
"Args": {
"restrictedToMinimumLevel": "Debug"
}
},
{
"Name": "MySink",
"Args": {
"restrictedToMinimumLevel": "Warning"
}
}
]
}
Can I use the Args to injection IHttpClientFactory?
Or handle this in Main method?
Note: I am using net core console application.
Update: According to the asnwer
Now, the Program Main is:
class Program
{
static async Task Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddHttpClient();
serviceCollection.AddSingleton<Serilog.ILogger>(sp =>
{
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
return new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.MySink(httpClientFactory)
.CreateLogger();
});
serviceCollection.AddLogging(configure => configure.ClearProviders().AddSerilog());
var serviceProvider = serviceCollection.BuildServiceProvider();
Log.Logger = serviceProvider.GetRequiredService<Serilog.ILogger>();
}
}
And I can injection ILogger in other class
class Test
{
private readonly ILogger<Test> _logger;
Test(ILogger<Test> logger)
{
_logger = logger;
}
}
Update: (2020-07-01)
Now, in asp net core, this package supply dependency injection.
.UseSerilog((hostingContext, services, loggerConfiguration) => loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
.Enrich.FromLogContext()
.WriteTo.SomeSink(services.GetRequiredService<ISomeDependency>()));
I have played around a bit and found you can use an implementation factory to get the IHttpClientFactory
after the service provider has been built. You need to change the service.AddLogging(...) call to use this factory implementation:
static async Task Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddHttpClient();
serviceCollection.AddSingleton<Serilog.ILogger>(sp =>
{
var httpClientFactory = sp.GetRequiredService<IHttpClientFactory>();
return new LoggerConfiguration()
.MinimumLevel.Debug()
//.ReadFrom.Configuration(Configuration)
.WriteTo.MySink(httpClientFactory)
.CreateLogger();
});
serviceCollection.AddLogging(cfg =>
{
cfg.ClearProviders().AddSerilog();
});
var serviceProvider = serviceCollection.BuildServiceProvider();
var logger = serviceProvider.GetService<Serilog.ILogger>();
logger.Debug("Working");
}
In the code sample we can use a factory implementation for AddSingleton
to only create the logger when it is first requested. This allows us to pull any registered services from the service provider and inject them into our class. In this case, we get the IHttpClientFactory
and inject it into MySink
.
If you put a breakpoint on the line var logger = serviceProvider.GetService<Serilog.ILogger>()
when you step into that it will call the lambda in AddSingleton
and create your logger for you.