.NET中如何为单个操作实现日志范围隔离?
给跨类异步日志自动添加流ID的解决方案
要实现让AudioSource和VideoSource的日志自动带上流ID,且无需修改这两个类的代码,核心是利用.NET日志系统的Scope上下文传递特性,结合AsyncLocal自动跟踪异步调用链的机制:
- 在
Stream方法中创建包含流ID的日志Scope
把启动异步任务的逻辑包裹在BeginScope创建的上下文中,这样所有异步任务内的日志都会自动继承这个Scope的上下文信息:
void Stream(string id) { var audio = new AudioSource(loggerFactory.CreateLogger<AudioSource>()); var video = new VideoSource(loggerFactory.CreateLogger<VideoSource>()); // 创建包含流ID的日志Scope,覆盖后续异步任务的执行周期 using (loggerFactory.CreateLogger<StreamHandler>().BeginScope(new Dictionary<string, object> { ["StreamId"] = id })) { Task.Run(() => { foreach (var frame in video.GetEnumerable()) SendVideo(id, frame); }); Task.Run(() => { foreach (var frame in audio.GetEnumerable()) SendAudio(id, frame); }); } }
- 配置日志输出模板(可选)
如果需要在日志中显式输出StreamId,可以修改日志配置(比如appsettings.json),在格式字符串中加入{StreamId}:
{ "Logging": { "Console": { "FormatterName": "simple", "FormatterOptions": { "Format": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {StreamId} {Message}{NewLine}{Exception}" } } } }
原理说明
.NET日志系统的BeginScope会将上下文信息存储在AsyncLocal变量中,异步任务在执行时会自动继承当前的AsyncLocal上下文。因此,AudioSource中log.LogDebug输出的日志会自动关联到外层创建的Scope,无需让AudioSource知晓流ID的存在,最终日志会包含StreamId信息。
内容的提问来源于stack exchange,提问作者LOST
相关产品推荐
相关产品推荐

