如何让Logger.BeginScope在.NET Core 2.0中与Application Insights正常工作?
你遇到的情况是对的——.NET Core 2.0对应的Application Insights ILogger默认实现确实不会自动将BeginScope中的内容附加到跟踪日志里,不是你配置错了,而是需要额外的设置或者SDK版本升级来实现这个功能。下面给你两种可行的解决办法:
方法1:自定义TelemetryInitializer提取Scope信息
Application Insights允许通过ITelemetryInitializer来修改或补充遥测数据,我们可以用它来把Scope的内容添加到跟踪日志的自定义属性中。
步骤1:实现自定义TelemetryInitializer
如果是Web应用,可以借助IHttpContextAccessor来传递Scope信息;如果是非Web场景,用AsyncLocal来存储当前Scope:
Web场景示例:
public class ScopeTelemetryInitializer : ITelemetryInitializer { private readonly IHttpContextAccessor _httpContextAccessor; public ScopeTelemetryInitializer(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public void Initialize(ITelemetry telemetry) { if (telemetry is TraceTelemetry traceTelemetry) { // 从HttpContext中读取预先存储的Scope内容 if (_httpContextAccessor.HttpContext?.Items.TryGetValue("CurrentScope", out var scopeValue) == true) { traceTelemetry.Properties["Scope"] = scopeValue.ToString(); } } } }
非Web场景(用AsyncLocal):
先创建一个静态类存储Scope:
public static class CurrentScopeHolder { private static readonly AsyncLocal<string> _currentScope = new AsyncLocal<string>(); public static string Value { get => _currentScope.Value; set => _currentScope.Value = value; } }
然后修改TelemetryInitializer:
public class ScopeTelemetryInitializer : ITelemetryInitializer { public void Initialize(ITelemetry telemetry) { if (telemetry is TraceTelemetry traceTelemetry && !string.IsNullOrEmpty(CurrentScopeHolder.Value)) { traceTelemetry.Properties["Scope"] = CurrentScopeHolder.Value; } } }
步骤2:注册TelemetryInitializer
在Startup.cs的ConfigureServices方法中注册这个初始化器:
public void ConfigureServices(IServiceCollection services) { // 注册Application Insights services.AddApplicationInsightsTelemetry(); // 注册自定义初始化器 services.AddSingleton<ITelemetryInitializer, ScopeTelemetryInitializer>(); // 别忘了注册IHttpContextAccessor(Web场景需要) services.AddHttpContextAccessor(); // 其他服务配置... }
步骤3:在BeginScope时存储Scope内容
使用Scope的时候,把内容存入对应的存储位置:
// Web场景 using (_logger.BeginScope("Some really useful information")) { HttpContext.Items["CurrentScope"] = "Some really useful information"; _logger.LogError("Oh no."); } // 非Web场景 using (_logger.BeginScope("Some really useful information")) { CurrentScopeHolder.Value = "Some really useful information"; _logger.LogError("Oh no."); }
这样,你在Application Insights的跟踪日志里就能看到名为Scope的自定义属性,值就是你传入的内容了。
方法2:升级Application Insights SDK版本
更简单的方式是升级Microsoft.ApplicationInsights.AspNetCore包到2.1.0及以上版本——这个版本开始,SDK默认支持将BeginScope的内容自动附加到跟踪日志的自定义属性中,无需额外代码。
因为你用的是.NET Core 2.0,2.1.0版本的SDK是兼容的,直接在NuGet包管理器中升级即可。升级后:
- 如果你的Scope是字符串(比如
BeginScope("xxx")),会自动添加一个名为Scope的自定义属性 - 如果你的Scope是字典类型(比如
BeginScope(new Dictionary<string, object> { { "UserId", "123" } })),字典里的每个键值对都会作为单独的自定义属性出现在跟踪日志里
两种方法都能解决你的问题,推荐优先尝试升级SDK,这样最省心;如果因为项目限制无法升级,再用自定义TelemetryInitializer的方式。
内容的提问来源于stack exchange,提问作者jsk

