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

添加自定义ActivitySource后.NET API的OpenTelemetry端点追踪失效问题

.NET REST API中OpenTelemetry追踪异常问题

在包含后台服务的.NET REST API项目中配置OpenTelemetry,用于追踪端点调用和服务活动。未添加.AddSource(CustomActivitySources.MessageServiceSource.Name)时,端点追踪正常;添加后所有端点请求的追踪完全停止生成。预期自定义活动源与AspNetCore端点追踪是独立功能,不应互相影响,需解决该问题。

原因分析

问题根源在CustomActivitySources静态构造函数中注册的全局ActivityListener:

  • 该监听器设置ShouldListenTo = _ => true,会监听所有ActivitySource创建的活动
  • 它的Sample方法返回ActivitySamplingResult.AllData,但这个全局监听器的采样逻辑会直接覆盖OpenTelemetry TracerProvider的采样配置(包括你设置的AlwaysOnSampler)
  • 添加自定义AddSource后,OpenTelemetry的TracerProvider与全局ActivityListener产生冲突,导致AspNetCore instrumentation生成的活动被错误拦截,最终无法导出

修复方法

方案1:移除全局ActivityListener(推荐)

OpenTelemetry已自带完整的采样和追踪处理逻辑,无需额外注册全局ActivityListener。修改CustomActivitySources类:

internal static class CustomActivitySources
{
    internal static readonly ActivitySource MessageServiceSource = new("MessageService");

    // 移除静态构造函数中的全局ActivityListener
}

方案2:限制全局ActivityListener的监听范围

若必须保留全局监听器,修改ShouldListenTo仅监听自定义活动源,避免干扰OpenTelemetry内置instrumentation:

static CustomActivitySources()
{
    ActivitySource.AddActivityListener(new ActivityListener()
    {
        ShouldListenTo = source => source.Name == MessageServiceSource.Name,
        Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllData,
    });
}

方案3:调整OpenTelemetry配置顺序(临时规避)

确保AddAspNetCoreInstrumentation()和AddHttpClientInstrumentation()在AddSource()之前调用,仅作为临时解决方式,推荐优先使用前两种方案:

tracerProviderBuilder
    .SetSampler(new AlwaysOnSampler())
    .AddAspNetCoreInstrumentation()
    .AddHttpClientInstrumentation()
    .AddSource(CustomActivitySources.MessageServiceSource.Name)
    .AddProcessor<TracerEndPointsFilterProcessor>();

相关指导

  • 避免混用全局ActivityListener与OpenTelemetry:OpenTelemetry通过TracerProvider统一管理追踪,全局ActivityListener会绕过其逻辑,引发冲突
  • 自定义活动源正确用法:只需创建ActivitySource实例,通过OpenTelemetry的.AddSource()注册,由OpenTelemetry统一处理采样、导出
  • 更优雅的端点过滤方式:推荐使用AspNetCoreInstrumentationOptions的Filter配置替代自定义处理器修改ActivityTraceFlags:
    .AddAspNetCoreInstrumentation(options =>
    {
        options.Filter = context => 
            !context.Request.Path.StartsWithSegments("/version") &&
            !context.Request.Path.StartsWithSegments("/health") &&
            !context.Request.Path.StartsWithSegments("/swagger");
    })
    
  • 版本升级建议:当前OpenTelemetry.Instrumentation.AspNetCore版本为1.0.0-rc9.11,建议升级到稳定版(如1.5.1),规避旧版本已知问题

原始代码参考

包引用

<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.3.2" />
<PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.3.2" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc9.11" />

初始追踪配置

services.AddOpenTelemetry()
        .ConfigureResource(resourceBuilder =>
        {
            resourceBuilder.AddService(
                serviceName: "main service name",
                serviceVersion: "1",
                serviceInstanceId: Environment.MachineName);
        })
        .WithTracing(tracerProviderBuilder =>
        {
            tracerProviderBuilder
                .SetSampler(new AlwaysOnSampler())
                .AddSource(CustomActivitySources.MessageServiceSource.Name)
                .AddProcessor<TracerEndPointsFilterProcessor>() 
                .AddHttpClientInstrumentation()
                .AddAspNetCoreInstrumentation();
        });

自定义处理器TracerEndPointsFilterProcessor

internal sealed class TracerEndPointsFilterProcessor : BaseProcessor<Activity>
{
    public override void OnEnd(Activity activity)
    {
        if (IsHealthOrMetricsEndpoint(activity.DisplayName))
        {
            activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded;
        }
    }

    private static bool IsHealthOrMetricsEndpoint(string displayName)
    {
        if (string.IsNullOrEmpty(displayName))
        {
            return false;
        }

        return
            displayName.StartsWith("/version", StringComparison.CurrentCultureIgnoreCase) ||
            displayName.StartsWith("/health", StringComparison.CurrentCultureIgnoreCase) ||
            displayName.StartsWith("/swagger", StringComparison.CurrentCultureIgnoreCase);
    }
}

自定义活动源类CustomActivitySources

internal static class CustomActivitySources
{
    internal static readonly ActivitySource MessageServiceSource = new("MessageService");

    static CustomActivitySources()
    {
        ActivitySource.AddActivityListener(new ActivityListener()
        {
            ShouldListenTo = _ => true,
            Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllData,
        });
    }
}

非HTTP服务活动使用示例

var initialTags = new ActivityTagsCollection
                {
                    // some tags
                };
const string activityName = "ServiceName";

activity = CustomActivitySources.MessageServiceSource.StartActivity(activityName,
                    ActivityKind.Consumer,
                    "trace id", initialTags);

内容的提问来源于stack exchange,提问作者Katia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 06:45:36