opentelemetry sdk 必须在 webapplicationbuilder 阶段初始化,显式设置 service.name,正确配置 otlp 协议(grpc 或 http/json),手动创建 span 时需通过 propagator 提取父上下文,httpclient 需启用 enablehttpheadersinjection 才能传递 trace 上下文。

OpenTelemetry SDK 初始化必须在应用启动早期完成
如果在 Program.cs 中延迟注册或依赖服务已构建后再配置 OpenTelemetry,会导致部分 HTTP 请求、数据库调用等自动检测(auto-instrumentation)丢失 span。ASP.NET Core 6+ 推荐在 WebApplicationBuilder 阶段就添加 tracing 服务。
实操建议:
- 使用
AddOpenTelemetryTracing扩展方法,而非手动 newTracerProvider,避免生命周期管理错误 - 必须调用
SetResourceBuilder显式设置 service.name,否则后端(如 Jaeger、OTLP Collector)无法按服务归类数据 - 启用
ActivitySource.Create的自定义追踪前,确认未被AspNetCoreInstrumentation或HttpClientInstrumentation覆盖
示例关键片段:
builder.Services.AddOpenTelemetryTracing(tracerProviderBuilder =>
{
tracerProviderBuilder
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("my-api"))
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddOtlpExporter(opt => opt.Endpoint = new Uri("http://localhost:4317"));
});
OTLP 协议导出需注意 gRPC vs HTTP/JSON 传输差异
默认 OtlpExporter 使用 gRPC(http://localhost:4317),但若后端只支持 HTTP/JSON(如某些旧版 Collector 配置),会静默失败——没有异常,但 spans 不出现。
常见错误现象:
- 日志里反复出现
ExportProcessor.OnExportAsync: Export failed,但无堆栈 - Wireshark 抓包发现客户端尝试 gRPC 连接,而服务端只监听
:4318
解决方式:
- 改用 HTTP/JSON 导出:设置
Protocol = OtlpExportProtocol.HttpProtobuf,endpoint 改为http://localhost:4318/v1/traces - 确保 Collector 配置中同时启用了
otlp/<code> 接收器,并区分 <code>grpc_endpoint和http_endpoint - 开发期可临时启用
ConsoleExporter验证 trace 是否生成成功,绕过网络环节
手动创建 Span 时必须显式链接父上下文
在非 HTTP 入口(如后台队列消费、TimerCallback、gRPC ServerStreaming)中,Activity.Current 通常为 null,直接 StartActivity 会产生孤立 span,断开调用链。
正确做法是通过 Propagators.Extract 从消息头(如 RabbitMQ headers、Kafka headers)还原上下文:
- 使用
B3Propagator或TraceContextPropagator,取决于上下游系统约定的传播格式 - 提取后调用
ActivitySource.StartActivity(..., parentContext: extractedContext) - 避免用字符串拼接 traceId/spanId 手动构造
ActivityContext,易出格式错误(如缺失 trace-flags)
示例(从字典提取 B3 头):
var b3Propagator = new B3Propagator();
var extracted = b3Propagator.Extract(B3Propagator.ParseHeaders, headers, (h, k) => h.GetValueOrDefault(k));
using var activity = MyActivitySource.StartActivity("process-order", ActivityKind.Consumer, extracted.Context);
HttpClient 默认不传递 trace 上下文到外部服务
即使启用了 AddHttpClientInstrumentation(),.NET 默认仍不会将当前 trace context 注入 outgoing request headers,除非显式启用传播。
原因在于:.NET 的 HttpClient instrumentation 默认关闭了 Enrich 和 header 注入逻辑,仅采集本地耗时。
修复方式:
- 在
AddHttpClientInstrumentation中启用EnableHttpHeadersInjection = true - 确保目标服务也支持对应传播协议(如 W3C TraceContext),否则收到的 traceparent 可能被忽略
- 若调用的是遗留 Java 服务,可能需降级为 B3 格式,在
HttpClientInstrumentationOptions中指定Propagator = new B3Propagator()
这个点最容易被忽略——你看到自己的服务有 trace,但下游没关联,大概率卡在这里。










