C# 如何覆盖Autofac子作用域中的Serilog记录器?
我有一个基本的.NET核心通用主机,它使用Serilog和AutofacC# 如何覆盖Autofac子作用域中的Serilog记录器?,c#,.net-core,autofac,serilog,asp.net-core-hosted-services,C#,.net Core,Autofac,Serilog,Asp.net Core Hosted Services,我有一个基本的.NET核心通用主机,它使用Serilog和Autofac 公共类程序 { 公共静态异步任务主(字符串[]args) { var配置=CreateConfiguration(args); Logger.Logger=新的LoggerConfiguration() .ReadFrom.Configuration(配置) .CreateLogger(); 尝试 { 日志信息(“启动主机…”); 等待新的HostBuilder() .UseServiceProviderFactory(新
公共类程序
{
公共静态异步任务主(字符串[]args)
{
var配置=CreateConfiguration(args);
Logger.Logger=新的LoggerConfiguration()
.ReadFrom.Configuration(配置)
.CreateLogger();
尝试
{
日志信息(“启动主机…”);
等待新的HostBuilder()
.UseServiceProviderFactory(新的AutofacServiceProviderFactory())
.ConfigureHostConfiguration(cb=>cb.AddConfiguration(配置))
.ConfigureServices((ctx、sc)=>{
sc.AddLogging(lb=>lb.AddSerilog());
})
.ConfigureContainer(cb=>{
注册表模块(新的AppModule());
})
.RunConsoleAsync();
}
捕获(例外情况除外){
Log.Fatal(例如,“主机意外终止”);
}
最后{
Log.CloseAndFlush();
}
}
专用静态IConfiguration CreateConfiguration(IReadOnlyCollection参数)
{
返回新的ConfigurationBuilder()
.AddJsonFile(“appsettings.json”,false,true)
.AddUserSecrets(true)
.AddCommandLine(args.ToArray())
.Build();
}
}
AppModule
是一个Autofac模块,我在其中注册了IHostedService
内部类AppModule:模块
{
受保护的覆盖无效负载(ContainerBuilder builder)
{
建筑商登记(
ctx=>{
var c=ctx.Resolve();
返回新的AutofacHostedServiceScopeOwner(
()=>c.Resolve()
.BeginLifetimeScope(b=>b.Register(x=>Log.Logger.ForContext(“名称”、“值”)).As(),
scope=>newmessageprocessingservice(
scope.Resolve()
)
);
}
)
.As();
}
}
这部分看起来很复杂,但我试图完成的是在Autofac子作用域中运行MessageProcessingService
(一个IHostedService
实现),这样我就可以用一些特定于上下文的信息覆盖整个MessageProcessingService
图中已解析的记录器。将有多个MessageProcessingService
实例,每个实例都需要一个具有唯一上下文的记录器,以便我可以关联日志输出
我使用AutofacHostedServiceScopeOwner
在子作用域中包装MessageProcessingService
。也许有更好的方法,但这是我能想到的最好的方法
公共类AutofacHostedServiceScopeOwner:IHostedService,IDisposable
{
私有只读函数;
私有只读函数服务工厂;
专用ILifetimeScope\u currentScope;
私人IHostedService(u hostedService);;
公共AutofacHostedServiceScopeOwner(Func scopeFactory、Func serviceFactory){
_scopeFactory=scopeFactory;
_服务工厂=服务工厂;
}
公共异步任务StartAsync(CancellationToken CancellationToken){
_currentScope=_scopeFactory();
_hostedService=\u serviceFactory(\u currentScope);
wait_hostedService.StartAsync(取消令牌);
}
公共异步任务StopAsync(CancellationToken CancellationToken){
if(_hostedService!=null)
wait_hostedService.stopsync(cancellationToken);
_currentScope?.Dispose();
}
公共空间处置(){
_currentScope?.Dispose();
}
}
除了解析的记录器不包含预期的上下文属性外,所有这些都正常工作。这让我觉得我的覆盖逻辑是错误的,但我不确定还有什么可以尝试
c.Resolve<ILifetimeScope>()
.BeginLifetimeScope(
b => b.Register(x => Log.Logger.ForContext("name", "value")).As<Serilog.ILogger>()
)
我在头撞了几个小时后才明白这一点
builder.Register(
ctx=>{
var c=ctx.Resolve();
返回新的AutofacHostedServiceScopeOwner(
()=>c.Resolve()
.BeginLifetimeScope(
b=>{
b、 RegisterGeneric(typeof(Logger)).As(typeof(ILogger));
b、 登记册(
x=>new SeriologgerFactory(
Log.Logger.ForContext(“名称”、“值”)
)
)
.As()
.InstancePerLifetimeScope();
}
),
scope=>newmessageprocessingservice(
scope.Resolve()
)
);
}
)
.As();
之所以这样做,是因为在Program.cs
中,记录器配置调用sc.AddLogging(lb=>lb.AddSerilog())
将ILogger
和ILoggerFactory
注册为盖下的单例。lb.AddSerilog()
调用注册了一个Serilog提供程序,该提供程序由ILoggerFactory
使用,但我无法找到任何方法专门覆盖该提供程序,因此我将其全部替换
希望这能帮助一些人。更换整个记录器工厂似乎很昂贵。“你考虑过吗?”Travigig我考虑过了,但不确定如何把它应用到一个范围内。我还尝试了LogContext.PushProperty,但也没有找到答案。
{
"Serilog": {
"Enrich": [ "FromLogContext" ],
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "Console"
}
]
}
}