Custom Serilog sink with injection?(自定义Serilog水槽与注入?)
问题描述
我创建了一个简单的Serilog接收器项目,如下所示:
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)});
}
}
}
消费微服务如下启动:
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();
appsettings.json的serilog部分如下所示:
"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": {}
}
]
}
添加MQSink项目作为对微服务项目的引用,我可以看到MQSink DLL最终位于bin文件夹中。
问题是在执行_logger.LogInformation(...)在微服务中,发送永远不会被触发,但如果我添加一个控制台接收器,它会输出数据吗?我还怀疑注入的MQ无法正常工作?如何解决此问题?
编辑:
打开Serilog内部日志,可以看到找不到MessageQueueSink方法。我没有找到任何使用appsetings.json的方法,所以我开始研究如何在代码中绑定它。要使其正常工作,需要创建一个扩展:
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));
}
}
这使得可以按如下方式添加自定义接收器:
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();
加载了自定义接收器并触发了发出,但我仍然不知道如何将MQ注入接收器中?如果我能在appsettings.json文件中完成Serilog和接收器的所有配置,那就更好了。
推荐答案
@pfx帮助我如何加载Serilog定制接收器,为此我给了他赏金,谢谢!然而,这并不是我的最终解决方案。
依赖项注入意味着类的构造函数将接受必要的对象作为参数。虽然无法使用构造函数参数加载自定义接收器,但必须通过该服务来完成。
public static IHost CreateHostBuilder(string[] args)
=> Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services
.AddTransient<IMyService, MyService>()
.AddTransient<ICommunicator, Communicator>()
.AddTransient<ILogEventSink, CustomSerilogSink>();
})
.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.WriteTo.Console(LogEventLevel.Information)
.Enrich.FromLogContext())
.Build();
}
问题是MQ控制器类注入了ILogger,这创建了一个循环引用,从而导致释放。MQ控制器是共享的,所以我不能对其进行太多更改,但我可以将所需的方法设置为静态的。而不是使用本地MQ对象,而是将它们发送到方法中。
但是,我无法删除MS ILogger要求,并且我仍然需要能够在自定义接收器中进行日志记录。因此,首先我创建了一个如下所示的Serilog:private static readonly ILogger _logger = Log.ForContext<MessageQueueSink>() as ILogger;
然后可以将此记录器包装在MS Ilogger类中,并将其发送到静态生产者方法:
public class CustomSerilogger : Microsoft.Extensions.Logging.ILogger
{
private readonly ILogger _logger;
public CustomSerilogger(ILogger logger)
{ _logger = logger; }
public IDisposable BeginScope<TState>(TState state) => default!;
public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel) { return _logger.IsEnabled(LogLevelToLogEventLevel(logLevel)); }
public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, Microsoft.Extensions.Logging.EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel))
return;
_logger.Write(LogLevelToLogEventLevel(logLevel), exception, state.ToString());
}
private LogEventLevel LogLevelToLogEventLevel(Microsoft.Extensions.Logging.LogLevel loglevel)
{
switch(loglevel)
{
case Microsoft.Extensions.Logging.LogLevel.Debug:
return LogEventLevel.Debug;
case Microsoft.Extensions.Logging.LogLevel.Information:
return LogEventLevel.Information;
case Microsoft.Extensions.Logging.LogLevel.Warning:
return LogEventLevel.Warning;
case Microsoft.Extensions.Logging.LogLevel.Error:
return LogEventLevel.Error;
case Microsoft.Extensions.Logging.LogLevel.Critical:
return LogEventLevel.Fatal;
case Microsoft.Extensions.Logging.LogLevel.None:
return LogEventLevel.Verbose;
case Microsoft.Extensions.Logging.LogLevel.Trace:
return LogEventLevel.Verbose;
}
return LogEventLevel.Verbose;
}
}
若要配置接收器,我必须在appsettings.json文件中创建自定义接收器设置部件,然后将其读取到设置对象中。
var mqSinkSettings = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build()
.GetSection("MessageQueueSinkSettings").Get<MessageQueueSinkSettings>();
终于成功了!
这篇关于自定义Serilog水槽与注入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:自定义Serilog水槽与注入?
- Windows 喜欢在 LINUX 中使用 MONO 进行服务开发? 2022-01-01
- 是否可以在 .Net 3.5 中进行通用控件? 2022-01-01
- C# 通过连接字符串检索正确的 DbConnection 对象 2022-01-01
- CanBeNull和ReSharper-将其用于异步任务? 2022-01-01
- 带问号的 nvarchar 列结果 2022-01-01
- 在 LINQ to SQL 中使用 contains() 2022-01-01
- 在 C# 中异步处理项目队列 2022-01-01
- 为什么 C# 中的堆栈大小正好是 1 MB? 2022-01-01
- Azure Active Directory 与 MVC,客户端和资源标识同一 2022-01-01
- 使用 rss + c# 2022-01-01