.NET中实现长期存活日志作用域的可行方案
.NET中实现跨方法存活的日志作用域
需求:在.NET中为日志作用域添加信息,且该作用域需存活超过单个方法调用。
常规日志作用域用法
常规使用方式是在单个方法内用using包裹作用域,示例代码:
public void DoSomething() { using(Logger.BeginScope("Instance id {Guid}", strGuid)) { Logger.LogInformation("did something"); } }
这种方式的问题是必须为每个公共方法添加BeginScope调用进行包裹,代码冗余且容易遗漏。
构造函数创建作用域的尝试(不可行)
曾尝试在类的构造函数中创建日志作用域,在Dispose方法中释放,代码如下:
public class SampleService : IDisposable { public readonly ILogger<SampleService> Logger; private IDisposable _logScope; public SampleService(ILogger<SampleService> logger) { Logger = logger; _logScope = Logger.BeginScope("Instance id {Guid}", Guid.NewGuid().ToString()); } public void DoSomething() { Logger.LogInformation("did something"); } public void Dispose() { _logScope?.Dispose(); } }
但该方案不可行,因为ILogger<T>是单例服务,多线程环境下不同实例的日志作用域会互相干扰,导致日志作用域信息混乱。
当前后台服务场景的实现
当前存在多个后台服务实例按需执行任务,要求为每个后台工作实例创建专属服务作用域,实现代码如下:
public class BackgroundWorker1 : BackgroundService { private string _workerInstance = Guid.NewGuid().ToString(); private IDisposable _logScope; private IServiceScope _serviceScope; public readonly IServiceScopeFactory ServiceScopeFactory; public ILogger<BackgroundWorker1> Logger; private IServiceProvider _serviceProvider; public BackgroundWorker1(IServiceScopeFactory serviceScopeFactory) { ServiceScopeFactory = serviceScopeFactory; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _serviceScope = ServiceScopeFactory.CreateScope(); _serviceProvider = _serviceScope.ServiceProvider; Logger = _serviceProvider.GetRequiredService<ILogger<BackgroundWorker1>>(); _logScope = Logger.BeginScope("worker instance id {WorkerId}", _workerInstance); } public void OneOfManyExternallyCalledMethods() { var service = _serviceProvider.GetRequiredService<Some3rdPartyService>(); service.DoSomething(); // 要求所有日志(包括第三方/微软库的日志)都包含工作实例的GUID } public void Dispose() { _serviceScope?.Dispose(); _logScope?.Dispose(); } }
最终目标
- 每个工作实例的ID必须出现在所有相关日志中,包括第三方库、微软官方库产生的日志
- 部分可重写的服务需要携带自身的服务实例ID
内容的提问来源于stack exchange,提问作者monty
相关产品推荐
相关产品推荐

