跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

c# 如何用 OpenTelemetry 在c#微服务中实现分布式链路追踪

OpenTelemetry 是 CNCF 毕业项目,.NET 生态已全面转向;OpenTracing 已归档,ApplicationInsights 不兼容 OTLP,跨语言对接困难。 为什么直接用
OpenTelemetry.Sdk
而不是
OpenTracing
或旧版
ApplicationInsights
因为
OpenTelemetry
是当前 CNCF 毕业项目,.NET 生态已全面转向它;
OpenTracing
已归档,
ApplicationInsights
的 SDK 虽仍可用,但不兼容标准 OTLP 协议,跨语言对接会出问题。微服务场景下,必须统一用 OTLP 导出器才能和 Go/Java 服务共用 Jaeger 或 Tempo。 如何在 ASP.NET Core 服务中注入并配置
TracerProvider
核心是注册
TracerProvider
并启用自动仪表化(auto-instrumentation),同时指定 OTLP 导出目标。别漏掉
AddAspNetCoreInstrumentation()
和
AddHttpClientInstrumentation()
—— 否则 HTTP 入口和出站调用不会生成 span。
using OpenTelemetry; using OpenTelemetry.Exporter; using OpenTelemetry.Instrumentation.AspNetCore; using OpenTelemetry.Instrumentation.Http; var builder = WebApplication.CreateBuilder(args); builder.Services.AddOpenTelemetry() .WithTracing(tracerProviderBuilder => { tracerProviderBuilder .AddAspNetCoreInstrumentation() // 捕获 Controller 请求 .AddHttpClientInstrumentation() // 捕获 HttpClient 调用 .AddSource("MyService"); // 手动创建 span 时用的名称 if (builder.Environment.IsDevelopment()) { tracerProviderBuilder.AddConsoleExporter(); } else { tracerProviderBuilder.AddOtlpExporter(opt => { opt.Endpoint = new Uri("http://otel-collector:4317"); // 注意:gRPC 端口是 4317,HTTP 是 4318 }); } }); var app = builder.Build(); app.UseRouting(); app.UseEndpoints(endpoints => endpoints.MapControllers()); app.Run();
OTLP gRPC endpoint
必须用
http://
协议(即使走 gRPC),.NET SDK 不支持
https://
自签名证书直连,生产环境需配 TLS 或改用 HTTP/JSON 导出器 本地调试时优先用
AddConsoleExporter()
,避免依赖外部 collector;输出含 trace-id、span-id、parent-id,可快速验证链路是否串联
AddSource("MyService")
是手动埋点的入口名,后续用
TracerProvider.Default.GetTracer("MyService")
获取 tracer 怎么让跨服务的 HTTP 调用自动传递 trace context .NET 的
HttpClient
自动注入
traceparent
header,但前提是:你用的是
IHttpClientFactory
创建的 client,且没手动 new
HttpClient
。手动 new 会绕过 instrumentation,导致下游收不到 context。 C知道 CSDN推出的一款AI技术问答工具 下载 ✅ 正确方式:在
Program.cs
注册命名 client:
builder.Services.AddHttpClient();
❌ 错误方式:
var client = new HttpClient();
—— 这个 client 完全不参与 OpenTelemetry 链路 如果必须用自定义
HttpClient
,得手动注入 context:
activity?.SetTag("http.url", url);
,但无法自动关联 parent-span 检查 trace 是否断开:看下游服务 log 中
traceparent
header 是否存在,值格式应为
00-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx-01
常见断链原因和验证手段 分布式链路“看起来有 trace-id,但 span 不连”是最常被忽略的问题。本质是 context 未正确传播或采样器丢弃了 span。 默认采样器是
ParentBasedSampler
,但如果上游没传 context,它会 fallback 到
NeverSample
—— 导致本服务第一个 span 就被丢弃。临时调试可强制用
AlwaysOnSampler
:
.SetSampler(new AlwaysOnSampler())
检查
Activity.Current
是否为 null:在 Controller action 开头加
Console.WriteLine(Activity.Current?.Id)
,若为 null,说明 instrumentation 未生效或中间件顺序错乱 ASP.NET Core 中间件顺序很重要:
UseRouting()
必须在
UseOpenTelemetryPrometheusScrapingEndpoint()
之前,否则路由未匹配就提前暴露指标端点 跨容器通信时,确保服务间 DNS 可解析(比如
otel-collector
是 Docker Compose service 名),别用
localhost
—— 容器内 localhost 指自己 链路追踪真正难的不是埋点,而是确认每个 hop 的 context 都没被意外截断或覆盖。建议上线前用一个简单请求跑通三跳链路(A → B → C),再逐个服务查
traceparent
header 和 span duration 是否合理。

相关文章