Ban*_*hee 8 c# code-injection serilog ilogger
我创建了一个简单的 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)});
}
}
}
Run Code Online (Sandbox Code Playgroud)
消费微服务的启动方式如下:
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();
Run Code Online (Sandbox Code Playgroud)
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": {}
}
]
}
Run Code Online (Sandbox Code Playgroud)
MQSink 项目被添加为微服务项目的引用,我可以看到 MQSink dll 最终位于 bin 文件夹中。
问题是,当在微服务中执行 _logger.LogInformation(...) 时,永远不会触发 Emit,但是如果我添加控制台接收器,它会输出数据吗?我也怀疑注入的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));
}
}
Run Code Online (Sandbox Code Playgroud)
这使得添加自定义接收器成为可能,如下所示:
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();
Run Code Online (Sandbox Code Playgroud)
自定义接收器已加载并触发 Emit,但我仍然不知道如何将 MQ 注入到接收器中?如果我可以在 appsettings.json 文件中完成 Serilog 和接收器的所有配置,那就更好了。
@pfx 帮助如何加载 Serilog 自定义接收器,为此我给了他赏金,谢谢!然而,这不是我的情况的最终解决方案。
\n依赖注入意味着类的构造函数将采用必要的对象作为参数。虽然\xe2\x80\x99s 不可能使用构造函数参数加载自定义接收器,但必须通过服务来完成。
\npublic static IHost CreateHostBuilder(string[] args)\n => Host.CreateDefaultBuilder(args)\n .ConfigureServices((hostContext, services) =>\n {\n services\n .AddTransient<IMyService, MyService>()\n .AddTransient<ICommunicator, Communicator>()\n .AddTransient<ILogEventSink, CustomSerilogSink>();\n })\n .UseSerilog((context, services, configuration) => configuration\n .ReadFrom.Configuration(context.Configuration)\n .ReadFrom.Services(services)\n .WriteTo.Console(LogEventLevel.Information)\n .Enrich.FromLogContext())\n .Build();\n }\nRun Code Online (Sandbox Code Playgroud)\n问题是 MQ 控制器类注入了一个 ILogger,这创建了一个循环引用,导致释放。MQ 控制器是共享的,因此我无法对其进行太多更改,但我可以将所需的方法设为静态。它们没有使用本地 MQ 对象,而是被发送到该方法中。
\n然而,我无法删除 MS ILogger 要求,并且我仍然需要能够在自定义接收器中登录。所以首先我创建了一个像这样的 Serilog:
\nprivate static readonly ILogger _logger = Log.ForContext<MessageQueueSink>() as ILogger;\nRun Code Online (Sandbox Code Playgroud)\n然后可以将该记录器包装在 MS Ilogger 类中并发送到静态生成器方法:
\npublic class CustomSerilogger : Microsoft.Extensions.Logging.ILogger\n{\n private readonly ILogger _logger;\n public CustomSerilogger(ILogger logger)\n { _logger = logger; }\n\n public IDisposable BeginScope<TState>(TState state) => default!;\n\n public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel) { return _logger.IsEnabled(LogLevelToLogEventLevel(logLevel)); }\n\n public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, Microsoft.Extensions.Logging.EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)\n {\n if (!IsEnabled(logLevel))\n return;\n\n _logger.Write(LogLevelToLogEventLevel(logLevel), exception, state.ToString());\n }\n\n private LogEventLevel LogLevelToLogEventLevel(Microsoft.Extensions.Logging.LogLevel loglevel)\n {\n switch(loglevel)\n {\n case Microsoft.Extensions.Logging.LogLevel.Debug:\n return LogEventLevel.Debug;\n case Microsoft.Extensions.Logging.LogLevel.Information:\n return LogEventLevel.Information;\n case Microsoft.Extensions.Logging.LogLevel.Warning:\n return LogEventLevel.Warning;\n case Microsoft.Extensions.Logging.LogLevel.Error:\n return LogEventLevel.Error;\n case Microsoft.Extensions.Logging.LogLevel.Critical:\n return LogEventLevel.Fatal;\n case Microsoft.Extensions.Logging.LogLevel.None:\n return LogEventLevel.Verbose;\n case Microsoft.Extensions.Logging.LogLevel.Trace:\n return LogEventLevel.Verbose;\n }\n return LogEventLevel.Verbose;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n要配置接收器,我必须在 appsettings.json 文件中创建自定义接收器设置部分,然后将其读入设置对象。
\nvar mqSinkSettings = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build()\n .GetSection("MessageQueueSinkSettings").Get<MessageQueueSinkSettings>();\nRun Code Online (Sandbox Code Playgroud)\n终于成功了!
\n| 归档时间: |
|
| 查看次数: |
5899 次 |
| 最近记录: |