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

如何通过外部包为.NET WebAPI注入OpenTelemetry Jaeger链路追踪

为.NET 7 WebAPI通过外部包注入OpenTelemetry Jaeger追踪的解决方案

问题1:基于ActivitySource监听请求的方式是否正确?

这个方向是正确的。ActivitySource是OpenTelemetry .NET实现中生成、管理追踪跨度(Activity)的核心组件,完全符合OpenTelemetry的规范。你之前手动注入ActivitySource加using块的方式能生成有效追踪,但重复编写代码的问题可以通过自动化手段解决,本身思路没问题。

问题2:若正确,如何动态为每个请求方法启动追踪,避免重复编写using块?

可以通过全局Action过滤器+ActivitySource的组合实现自动化追踪,不需要在每个控制器方法里写重复代码,具体步骤如下:

  1. 在类库中实现自定义Action过滤器,自动处理Activity的创建和结束:
public class JaegerTracingFilter : ActionFilterAttribute
{
    private readonly ActivitySource _activitySource;

    public JaegerTracingFilter(ActivitySource activitySource)
    {
        _activitySource = activitySource;
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var request = context.HttpContext.Request;
        // 创建Activity,设置Kind为Server(表示服务端接收请求的追踪跨度)
        using var activity = _activitySource.StartActivity(
            $"{request.Method} {request.Path}",
            ActivityKind.Server);
        
        // 将Activity存入HttpContext,方便后续扩展(比如添加自定义标签)
        context.HttpContext.Items["CurrentTraceActivity"] = activity;
        
        // 添加自定义标签,比如请求路径、方法等
        activity?.AddTag("http.method", request.Method);
        activity?.AddTag("http.path", request.Path);
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        if (context.HttpContext.Items.TryGetValue("CurrentTraceActivity", out var obj) && obj is Activity activity)
        {
            // 添加响应状态码标签
            activity.AddTag("http.status_code", context.HttpContext.Response.StatusCode);
            // 如果有异常,标记为错误
            if (context.Exception != null)
            {
                activity.SetStatus(ActivityStatusCode.Error);
                activity.RecordException(context.Exception);
            }
        }
    }
}
  1. 在类库中提供扩展方法,让WebAPI只需调用一次即可完成追踪配置(包括注册过滤器、ActivitySource、OpenTelemetry和Jaeger导出):
public static class JaegerTracingExtensions
{
    private const string ActivitySourceName = "YourCompany.WebApi.Tracing";

    public static IServiceCollection AddJaegerTracing(this IServiceCollection services, params string[] targetAssemblies)
    {
        // 注册ActivitySource为单例
        services.AddSingleton(new ActivitySource(ActivitySourceName));
        
        // 注册全局Action过滤器,仅对指定程序集的控制器生效
        services.AddMvc(options =>
        {
            options.Filters.AddService<JaegerTracingFilter>(int.MinValue);
        })
        .AddApplicationPart(Assembly.Load(targetAssemblies.First()));

        // 配置OpenTelemetry和Jaeger导出(复用你现有的控制台配置)
        services.AddOpenTelemetry()
            .WithTracing(tracerProviderBuilder =>
            {
                tracerProviderBuilder
                    .AddSource(ActivitySourceName)
                    .AddJaegerExporter(options =>
                    {
                        // 填入你的Jaeger配置
                        options.AgentHost = "localhost";
                        options.AgentPort = 6831;
                    });
            });

        // 注册过滤器服务
        services.AddScoped<JaegerTracingFilter>();

        return services;
    }
}
  1. WebAPI端只需在Program.cs中调用这个扩展方法即可,无需编写任何追踪相关的中间件或控制器代码:
var builder = WebApplication.CreateBuilder(args);

// 调用外部类库的扩展方法,传入要追踪的程序集名称
builder.Services.AddJaegerTracing("YourWebApi.AssemblyName");

// 其他原有配置...
var app = builder.Build();
// 原有中间件配置...
app.Run();

这种方式完全满足需求:所有追踪逻辑都在外部类库中,WebAPI只需要一行代码调用,自动为所有请求方法生成包含Activity.Kind的完整追踪。

问题3:若该方式错误,可使用OpenTelemetry的哪些方法实现需求?

如果不想用Action过滤器,还可以通过DiagnosticListener监听ASP.NET Core原生诊断事件的方式实现,ASP.NET Core会自动发出请求相关的诊断事件,我们可以在类库中订阅这些事件来生成追踪:

  1. 在类库中实现DiagnosticListener订阅者:
public class AspNetCoreTraceSubscriber : IObserver<DiagnosticListener>
{
    private readonly ActivitySource _activitySource;

    public AspNetCoreTraceSubscriber(ActivitySource activitySource)
    {
        _activitySource = activitySource;
    }

    public void OnNext(DiagnosticListener listener)
    {
        if (listener.Name == "Microsoft.AspNetCore")
        {
            listener.SubscribeWithAdapter(new HttpRequestObserver(_activitySource));
        }
    }

    public void OnCompleted() { }
    public void OnError(Exception error) { }
}

public class HttpRequestObserver
{
    private readonly ActivitySource _activitySource;

    public HttpRequestObserver(ActivitySource activitySource)
    {
        _activitySource = activitySource;
    }

    // 订阅请求开始事件
    [DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn.Start")]
    public void OnHttpRequestInStart(HttpContext context)
    {
        using var activity = _activitySource.StartActivity(
            $"{context.Request.Method} {context.Request.Path}",
            ActivityKind.Server);
        activity?.AddTag("http.method", context.Request.Method);
        activity?.AddTag("http.path", context.Request.Path);
        context.Items["CurrentTraceActivity"] = activity;
    }

    // 订阅请求结束事件
    [DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop")]
    public void OnHttpRequestInStop(HttpContext context)
    {
        if (context.Items.TryGetValue("CurrentTraceActivity", out var obj) && obj is Activity activity)
        {
            activity.AddTag("http.status_code", context.Response.StatusCode);
        }
    }
}
  1. 同样在扩展方法中注册订阅者和OpenTelemetry配置:
public static IServiceCollection AddJaegerTracing(this IServiceCollection services)
{
    var activitySource = new ActivitySource("YourCompany.WebApi.Tracing");
    services.AddSingleton(activitySource);
    services.AddSingleton<IObserver<DiagnosticListener>, AspNetCoreTraceSubscriber>();

    // 配置OpenTelemetry和Jaeger导出(同之前的代码)
    services.AddOpenTelemetry()
        .WithTracing(tracerProviderBuilder =>
        {
            tracerProviderBuilder
                .AddSource(activitySource.Name)
                .AddJaegerExporter(options =>
                {
                    options.AgentHost = "localhost";
                    options.AgentPort = 6831;
                });
        });

    return services;
}

这种方式不需要依赖Mvc过滤器,直接监听ASP.NET Core的原生事件,同样可以实现无侵入的追踪注入,适合不想依赖Mvc组件的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 15:27:46