商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > C#怎么使用System.Diagnostics.Activity_C#分布式追踪Activity教程【高级】

C#怎么使用System.Diagnostics.Activity_C#分布式追踪Activity教程【高级】

  发布于2026-07-06 阅读(0)

扫一扫,手机访问

分布式追踪这个话题,很多开发者一开始接触 System.Diagnostics.Activity 时,都会有一种“这 API 看着挺简单,用起来到处是坑”的感觉。今天就跟大家聊聊几个具体的技术细节,它们直接关系到你的 trace 能不能跑通、数据会不会丢。

先来一个最核心的判断:直接用 new Activity("name") 是跑不出有效 trace 的。重点来了——必须走 ActivitySource.StartActivity(),而且这个方法的返回值可能会是 null。注意,返回 null 不代表你的代码写错了,而是采样器在帮你“主动丢弃”。

StartActivity() 返回 null 的真相

很多人拿到 null 后第一反应是检查配置,其实这恰恰是正常情况。OpenTelemetry 默认的采样策略(比如 ParentBased)会依赖父上下文来决定是否创建 span。如果上游没有传 traceparent 头,或者当前服务根本没启用采样,那 StartActivity() 就会给它一个 null。这是系统在按规则做事,不是 BUG。

这个机制下有几个必须注意的点:

  • 忽略判空直接调用 SetTag()Stop(),必出 NullReferenceException
  • 别一看“没数据”就怀疑配置有问题,先看看是不是 trace 被合法丢弃了。
  • 开发阶段可以临时用 AddAlwaysOnSampler() 来验证逻辑,但上线前一定要切回合理策略。

ActivitySource.Name 的“静默杀手”

这个坑更隐蔽。你在代码里写了 new ActivitySource("user-service"),但在 TracerProviderBuilder 里只配置了 AddSource("userservice")——少了横杠。结果就是所有 activity 全部丢失,而且日志里一个字都不会报错。这才是真正让人抓狂的地方。

解决起来也很简单:建议统一用一个常量定义 source 名称,比如 public const string SourceName = "user-service";,然后在所有用到的地方直接引用。另外要提醒一下,ASP.NET Core 里的 AddAspNetCoreInstrumentation() 默认注册的 source 名是 Microsoft.AspNetCore.Hosting,不是你服务的名字——这一点很多人会搞混。

手动传播 traceparent 时,不要只传一个头

很多人在做跨服务传播时,只传了 traceparent,结果下游确实能拿到链路 ID,但像 tenant-id 这样的业务透传字段,以及供应商扩展字段,全部丢失了。这就是因为漏掉了 tracestatebaggage

正确的做法是:发送方需要同时写入 traceparenttracestatebaggage 三个头。接收方也不能仅仅用 ActivityContext.TryParse() 去解析 traceparent——还得手动重建 Baggage,用 ActivityContext.CreateBaggage(baggageHeader)。另外要注意,Baggage 本身是只读集合,要修改的话得用 WithBaggageItem("k", "v") 生成新实例。

跨线程环境下的 Activity.Current 问题

在 async/await 场景下,Activity.Current 会自动流转,问题不大。但一旦切换到 Task.Run(() => { ... }) 或者 ThreadPool.QueueUserWorkItem,上下文就会丢失。这时候千万不要自己去弄一个 AsyncLocal 来手动存取——Activity.Current 内部已经封装好了 AsyncLocal,你直接操作它反而会破坏内部一致性。

正确的做法是:在主线程捕获 Activity.Current?.Context,然后在子线程入口用 Activity.StartActivity("name", ActivityKind.Internal, context) 显式传入。另外有个建议:细粒度的 IO 操作,比如每读一个文件块都单独开 span,是没有必要的。应该按语义操作来建,比如 "File.Load.Config",否则会把 collector 压垮。

最后想说一个很容易被忽略的事实:Activity 并不是数据沿袭的工具。它不会管变量从哪里来、被谁修改过,它只负责记录“谁触发了谁”。如果想追踪文件内容的流向,那得自己设计 DataFlowContext 加上 AsyncLocal,强行套用 Activity 只会把语义搞乱。

C#怎么使用System.Diagnostics.Activity_C#分布式追踪Activity教程【高级】
本文转载于:https://www.php.cn/faq/2438868.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注