opentelemetry .net微服务链路追踪需注册tracerprovider并显式添加addaspnetcoreinstrumentation()和addhttpclientinstrumentation(),分别捕获http入口与出站调用;必须使用di管理的httpclient实例、统一otlp协议及16进制32位trace-id格式,否则跨服务链路中断。

直接用 OpenTelemetry.Sdk,别碰 OpenTracing 或旧版 ApplicationInsights ——前者已归档,后者不兼容 OTLP,跨服务链路必然断开。
ASP.NET Core 里怎么注册 TracerProvider 才能捕获 HTTP 入口和出站调用
必须显式添加两个自动仪表化组件:AddAspNetCoreInstrumentation() 和 AddHttpClientInstrumentation()。漏掉任意一个,Controller 请求或下游 HTTP 调用就不会生成 span,链路直接“断一截”。
-
AddAspNetCoreInstrumentation()捕获请求进入时的 span(含 route、status code、duration) -
AddHttpClientInstrumentation()捕获HttpClient发起的每个出站请求(自动注入traceparentheader) - 手动埋点要用
AddSource("MyService"),后续通过TracerProvider.Default.GetTracer("MyService")获取 tracer 实例 - 开发环境优先用
AddConsoleExporter(),输出含trace-id、span-id、parent-id的原始日志,一眼验证串联是否生效
OTLP 导出器 endpoint 写 http:// 却走 gRPC?为什么不能写 https://
.NET 的 OtlpExporter 默认走 gRPC,但 SDK 强制要求 endpoint 用 http:// 协议前缀——即使目标是 otel-collector:4317(gRPC 端口)。写成 https:// 会静默失败,且不报错。
- 生产环境若需 TLS,得在 collector 侧终止 TLS,应用侧仍用
http://otel-collector:4317 - 自签名证书场景下,改用 HTTP/JSON 导出器更稳妥:
AddOtlpExporter(opt => opt.Protocol = OtlpExportProtocol.HttpProtobuf),端口换为4318 - 本地调试时,collector 可用
otel/opentelemetry-collector-contrib:latest镜像,配好 receivers(otlp)、exporters(logging/jaeger)即可
HttpClient 调用为啥没传递 trace context
不是 HttpClient 本身问题,而是你没用对实例:必须从 DI 容器解析 HttpClient(即注册了 AddHttpClientInstrumentation() 后由框架创建的),自己 new 出来的 HttpClient 不受监控,也不会注入 traceparent。
- 检查是否用了
builder.Services.AddHttpClient<imyclient myclient>()</imyclient>这类注册方式 - 确保调用方构造函数中接收的是
IHttpClientFactory或泛型HttpClient,而非裸new HttpClient() - 跨服务调用返回 40x/50x 时,span 仍会生成,但 status code 会被标记为 ERROR;若完全没 span,大概率是 HttpClient 实例未被 instrumented
最易忽略的一点:所有服务必须统一用 OTLP 导出协议,哪怕只是临时加个 AddConsoleExporter(),也要确认它输出的 trace-id 格式和其他服务一致(16 进制 32 位),否则 Jaeger/Tembo 里看到的是一堆孤立的 trace。











