OpenTelemetry .NET SDK无Trace输出问题排查求助
问题:WebAPI中OpenTelemetry Trace无法输出及发送至Collector的排查
Metrics可正常发送到Prometheus并显示在控制台,但Trace既不输出到控制台,也未被OTel Collector接收(无日志记录),Grafana Tempo中也无数据。添加了ActivityListener后,控制台也没有任何Activity启动的输出。
原代码
using System.Diagnostics; using System.Diagnostics.Metrics; using OpenTelemetry.Exporter; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using OpenTelemetry.Trace; var builder = WebApplication.CreateBuilder(args); var metricCollectorUrl = builder.Configuration["OtelMetricCollector:Host"] ?? ""; var traceCollectorUrl = builder.Configuration["OtelTraceCollector:Host"] ?? ""; builder.Services .AddMetrics() .AddOpenTelemetry() .ConfigureResource(r => { r.AddService("OrderService"); }) .WithMetrics(m => { m.AddMeter("OrderServiceMeter") .AddOtlpExporter(o => { o.Protocol = OtlpExportProtocol.HttpProtobuf; o.Endpoint = new Uri(metricCollectorUrl); }) .AddConsoleExporter(); }) .WithTracing(t => { t.AddSource("Order Service APIs") .AddConsoleExporter() .AddOtlpExporter(o => { o.Protocol = OtlpExportProtocol.HttpProtobuf; o.Endpoint = new Uri(traceCollectorUrl); }); }); var app = builder.Build(); Counter<int>? otlOrderCount = null; ActivitySource.AddActivityListener(new ActivityListener() { ActivityStarted = r => { Console.WriteLine($"Activity {r.DisplayName} started."); } }); app.MapGet("/", async (context) => { using var activity = Activity.Current?.Start(); activity.SetTag("Service", "Order"); activity.DisplayName = "Order Processing"; var metricFactory = context.RequestServices.GetService<IMeterFactory>(); var meter = metricFactory?.Create(new MeterOptions("OrderServiceMeter")); otlOrderCount = meter?.CreateCounter<int>("otel_order"); otlOrderCount?.Add(1); using (var step1Activity = activity.Start()) // Create child spans within the root activity { step1Activity.SetTag("Step", "Get Customer Info."); step1Activity.DisplayName = "Customer Info"; step1Activity.SetStatus(ActivityStatusCode.Ok); } using (var step2Activity = activity.Start()) { step2Activity.SetTag("Step", "Get Shipping Info."); step2Activity.DisplayName = "Shipping Info"; step2Activity.SetStatus(ActivityStatusCode.Ok); } activity.SetStatus(ActivityStatusCode.Ok); // Set status on root activity }); app.Run();
代码中的错误点
Activity创建逻辑错误:
Activity.Current?.Start()无法创建有效的Activity,因为初始请求进来时Activity.Current为null,导致后续所有子Activity也无法生成。必须通过ActivitySource实例来启动Activity,且该实例的名称要和OTel配置中AddSource的名称一致。未启用ASP.NET Core请求追踪:OTel未配置捕获WebAPI的请求Activity,需要在
WithTracing中添加.AddAspNetCore(),否则WebAPI的请求不会被纳入Trace链路。ActivityListener未设置监听规则:添加的
ActivityListener没有配置ShouldListenTo委托,导致它不会监听任何ActivitySource,自然不会触发ActivityStarted事件。Metrics对象重复创建:每次请求都创建新的
Meter和Counter,这会导致Metrics数据混乱,不符合OTel的最佳实践,应该在应用启动时一次性创建。
修正后的代码示例
using System.Diagnostics; using System.Diagnostics.Metrics; using OpenTelemetry.Exporter; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using OpenTelemetry.Trace; var builder = WebApplication.CreateBuilder(args); var metricCollectorUrl = builder.Configuration["OtelMetricCollector:Host"] ?? ""; var traceCollectorUrl = builder.Configuration["OtelTraceCollector:Host"] ?? ""; // 全局定义ActivitySource,名称要和OTel配置中的AddSource一致 var activitySource = new ActivitySource("Order Service APIs"); // 全局创建Meter和Counter var meter = new Meter("OrderServiceMeter"); var otlOrderCount = meter.CreateCounter<int>("otel_order"); builder.Services .AddMetrics() .AddOpenTelemetry() .ConfigureResource(r => { r.AddService("OrderService"); }) .WithMetrics(m => { m.AddMeter(meter.Name) .AddOtlpExporter(o => { o.Protocol = OtlpExportProtocol.HttpProtobuf; o.Endpoint = new Uri(metricCollectorUrl); }) .AddConsoleExporter(); }) .WithTracing(t => { t.AddSource(activitySource.Name) // 添加ASP.NET Core请求追踪,捕获根请求Activity .AddAspNetCore() .AddConsoleExporter() .AddOtlpExporter(o => { o.Protocol = OtlpExportProtocol.HttpProtobuf; o.Endpoint = new Uri(traceCollectorUrl); }); }); var app = builder.Build(); // 配置ActivityListener,指定监听的ActivitySource ActivitySource.AddActivityListener(new ActivityListener() { ShouldListenTo = source => source.Name == activitySource.Name, ActivityStarted = r => { Console.WriteLine($"Activity {r.DisplayName} started."); } }); app.MapGet("/", async (context) => { // 使用全局ActivitySource创建根Activity using var activity = activitySource.StartActivity("Order Processing"); if (activity == null) return; activity.SetTag("Service", "Order"); activity.SetStatus(ActivityStatusCode.Ok); otlOrderCount.Add(1); // 创建子Activity using var step1Activity = activitySource.StartActivity("Customer Info", ActivityKind.Internal, activity.Context); if (step1Activity != null) { step1Activity.SetTag("Step", "Get Customer Info."); step1Activity.SetStatus(ActivityStatusCode.Ok); } using var step2Activity = activitySource.StartActivity("Shipping Info", ActivityKind.Internal, activity.Context); if (step2Activity != null) { step2Activity.SetTag("Step", "Get Shipping Info."); step2Activity.SetStatus(ActivityStatusCode.Ok); } }); app.Run();
内容的提问来源于stack exchange,提问作者Aref Karimi
相关产品推荐
相关产品推荐

