I have create a simple Serilog sink project that looks like this :
namespace MyApp.Cloud.Serilog.MQSink
{
public class MessageQueueSink: ILogEventSink
{
private readonly IMQProducer _MQProducerService;
public MessageQueueSink(IMQProducer mQProducerService)
{
_MQProducerService = mQProducerService;
}
public void Emit(LogEvent logEvent)
{
_MQProducerService.Produce<SendLog>(new SendLog() { LogEventJson = JsonConvert.SerializeObject(logEvent)});
}
}
}
The consuming microservice are starting up like this :
var configurationBuilder = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
var appSettings = configurationBuilder.Get<AppSettings>();
configurationBuilder = new ConfigurationBuilder().AddJsonFile("ExtendedSettings.json").Build();
Host.CreateDefaultBuilder(args)
.UseMyAppCloudMQ(context => context.UseSettings(appSettings.MQSettings))
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration))
.ConfigureServices((hostContext, services) =>
{
services
.AddHostedService<ExtendedProgService>()
.Configure<MQSettings>(configurationBuilder.GetSection("MQSettings"))
})
.Build().Run();
The serilog part of appsettings.json looks like this :
"serilog": {
"Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Console", "MyApp.Cloud.Serilog.MQSink" ],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId" ],
"WriteTo": [
{
"Name": "MessageQueueSink",
"Args": {}
}
]
}
The MQSink project is added as reference to the microservice project and I can see that the MQSink dll ends up in the bin folder.
The problem is that when executing a _logger.LogInformation(...) in the microservice the Emit are never triggered, but if I add a console sink it will output data? I also suspect that the injected MQ will not work properly?
How could this be solved?
EDIT :
Turned on the Serilog internal log and could see that the method MessageQueueSink could not be found. I did not find any way to get this working with appsetings.json so I started to look on how to bind this in code.
To get it working a extension hade to be created :
public static class MySinkExtensions
{
public static LoggerConfiguration MessageQueueSink(
this Serilog.Configuration.LoggerSinkConfiguration loggerConfiguration,
MyApp.Cloud.MQ.Interface.IMQProducer mQProducer = null)
{
return loggerConfiguration.Sink(new MyApp.Cloud.Serilog.MQSink.MessageQueueSink(mQProducer));
}
}
This made it possible to add the custom sink like this :
Host.CreateDefaultBuilder(args)
.UseMyAppCloudMQ(context => context.UseSettings(appSettings.MQSettings))
.ConfigureServices((hostContext, services) =>
{
services
.Configure<MQSettings>(configurationBuilder.GetSection("MQSettings"))
})
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration).WriteTo.MessageQueueSink())
.Build().Run();
The custom sink is loaded and the Emit is triggered but I still do not know how to inject the MQ in to the sink? It would also be much better if I could do all the configuration of the Serilog and sink in the appsettings.json file.
If you refer to the Provided Sinks list and examine the source code for some of them, you'll notice that the pattern is usually:
IConfiguration, inline or a combination of both)Then the sink implementation instantiates the required services to push logs to.
An alternate approach I could suggest is registering Serilog without any arguments (UseSerilog()) and then configure the static Serilog.Log class using the built IServiceProvider:
var host = Host.CreateDefaultBuilder(args)
// Register your services as usual
.UseSerilog()
.Build()
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(host.Services.GetRequiredService<IConfiguration>())
.WriteTo.MessageQueueSink(host.Services.GetRequiredService<IMQProducer>())
.CreateLogger();
host.Run();