如何配置Azure.Monitor.OpenTelemetry.AspNetCore为所有类型遥测添加自定义属性(而非仅请求跟踪)
嗨,我来帮你解决这个问题~你现在遇到的情况是自定义属性只加到了request遥测里,而trace遥测没加上,主要原因有两个:一是你的处理器依赖HttpContextAccessor,但很多非请求类的trace(比如数据库调用、自定义业务trace)启动时根本拿不到HttpContext;二是处理器的注册逻辑可能没覆盖到所有类型的Activity。
下面给你两个可行的解决方案,优先推荐第一个,因为它能覆盖所有请求链路内的trace,包括后台任务之外的所有场景:
方案一:用AsyncLocal全局传递CorrelationId(推荐)
这个思路是把CorrelationId存储在AsyncLocal容器里,这样同一个请求链路里的所有Activity(不管有没有直接关联HttpContext)都能拿到这个值,从而给对应的遥测添加自定义属性。
步骤1:创建Correlation上下文容器
先写一个静态类来存储AsyncLocal的CorrelationId:
public static class CorrelationContext { private static readonly AsyncLocal<string?> _correlationId = new(); // 获取当前上下文的CorrelationId public static string? CurrentCorrelationId => _correlationId.Value; // 设置CorrelationId public static void SetCorrelationId(string? id) => _correlationId.Value = id; }
步骤2:添加中间件初始化CorrelationId
在请求进入时,从HttpHeader里读取CorrelationId并写入AsyncLocal:
public class CorrelationIdMiddleware { private readonly RequestDelegate _next; public CorrelationIdMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { var correlationId = context.Request.Headers["correlation-id"].FirstOrDefault(); if (!string.IsNullOrEmpty(correlationId)) { // 写入AsyncLocal,供后续所有Activity使用 CorrelationContext.SetCorrelationId(correlationId); // 同时给当前请求的Activity直接加标签(保持原有逻辑) Activity.Current?.SetTag("CorrelationId", correlationId); } await _next(context); } } // 记得在Program.cs里注册中间件(要放在其他业务中间件之前) builder.Services.AddTransient<CorrelationIdMiddleware>(); app.UseMiddleware<CorrelationIdMiddleware>();
步骤3:修改处理器,不再依赖HttpContextAccessor
现在处理器可以直接从AsyncLocal拿CorrelationId,不用再依赖HttpContext了:
public class CorrelationIdActivityEnrichingProcessor(ILogger<CorrelationIdActivityEnrichingProcessor> logger) : BaseProcessor<Activity> { public override void OnStart(Activity activity) { var correlationId = CorrelationContext.CurrentCorrelationId; if (correlationId != null) { activity.SetTag("CorrelationId", correlationId); } } }
步骤4:调整处理器的注册位置
确保处理器被添加到全局的TracerProvider中:
builder.Services.AddOpenTelemetry() .WithTracing(tracerBuilder => { // 注册自定义处理器 tracerBuilder.AddProcessor(sp => new CorrelationIdActivityEnrichingProcessor( sp.GetRequiredService<ILogger<CorrelationIdActivityEnrichingProcessor>>() ) ); // 别忘了添加你需要的Instrumentation(比如AspNetCore、SqlClient等) tracerBuilder.AddAspNetCoreInstrumentation(); tracerBuilder.AddSqlClientInstrumentation(); }) .UseAzureMonitor(options => { options.EnableLiveMetrics = true; }) .ConfigureResource(resourceBuilder => { resourceBuilder.AddAttributes([ new KeyValuePair<string, object>("service.name", "MyApp") ]); });
这样修改后,同一个请求链里的所有trace(包括数据库调用、自定义业务Activity)都会带上CorrelationId属性。
方案二:调整处理器注册逻辑(仅适用于有HttpContext的场景)
如果你的所有trace都和请求强相关,也可以调整处理器的注册方式,确保它覆盖所有Azure Monitor的TracerProvider:
builder.Services.AddOpenTelemetry() .UseAzureMonitor(options => { options.EnableLiveMetrics = true; }) .WithTracing(tracerBuilder => { tracerBuilder.AddProcessor(sp => new CorrelationIdActivityEnrichingProcessor( sp.GetRequiredService<IHttpContextAccessor>(), sp.GetRequiredService<ILogger<CorrelationIdActivityEnrichingProcessor>>() ) ); tracerBuilder.AddAspNetCoreInstrumentation(); }) .ConfigureResource(resourceBuilder => { resourceBuilder.AddAttributes([ new KeyValuePair<string, object>("service.name", "MyApp") ]); });
不过这个方案还是依赖HttpContext,对于后台任务、定时任务这类没有HttpContext的trace,依然无法添加属性,所以优先级低于方案一。
最后提醒下:Azure Monitor会自动把Activity的标签转换成自定义属性,只要标签名称是合法的(比如不含特殊字符),就能在Application Insights里看到对应的属性啦。
备注:内容来源于stack exchange,提问作者Shuzheng

