You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置Azure.Monitor.OpenTelemetry.AspNetCore为所有类型遥测添加自定义属性(而非仅请求跟踪)

如何配置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 12:03:08