手动插桩
SDK 的大部分是自动插桩——您配置一次,由它决定记录什么。TracerService 是手动的那一半:把它注入到应用程序的任何位置,即可在已被追踪的请求内部添加跨度、为该请求附加上下文、捕获您自行处理的错误,以及上报您自己的指标。
TracerService 由 ObserveModule 导出,因此在导入该模块的任何模块中都可以注入。每个方法都会从环境异步上下文中读取追踪信息,这意味着在请求、任务或其他被插桩操作之外调用它们会抛出异常——因为没有可附加的追踪。这是有意为之:静默丢弃一个跨度比抛出错误更难察觉。(例外是自定义指标,它们不与追踪绑定。)
创建跨度
createSpan(name, callback) 会在一个新跨度内运行回调,该跨度嵌套在当前活动的跨度之下,并返回回调的返回值。跨度的持续时间就是回调的持续时间,因此任何您想测量的东西都要 await:
跨度按调用栈嵌套——一个 createSpan() 出现在另一个 createSpan() 的回调中,就成为后者的子跨度,这正是追踪详情页上瀑布图的成因。回调可以是同步的,也可以是异步的。自动插桩的跨度(控制器方法、提供者、数据库调用)与您的自定义跨度会归入同一棵树,因此手工命名的跨度会准确地出现在它实际运行的位置,与其他一切相对。
span 参数是一个 TraceSpanDelegate,其 addTags(tags)(或针对单个键值对的 setTag(key, value))仅把键值对附加到该跨度上。它们可以被搜索,并在追踪视图中显示在该跨度上,与 SDK → 标签和自定义属性中描述的 tags/setAttributes 选项相同——区别在于作用域:那些覆盖每个请求,而这个只覆盖单个跨度。
activeSpan() 返回当前活动跨度的 TraceSpanDelegate 而不创建新跨度,适用于您想从一段并非创建该跨度的代码中给外层跨度打标签的场景:
如果当前追踪没有活动跨度,它会抛出异常。

info 提示 跨度名称是跨度分析视图聚合的依据,横跨调用它们的所有路由。请选择描述工作内容的名称(
orders.recalculate、cache.lookup),而不是描述调用者,这样"它在所有地方都慢,还是只在这个端点慢?"就成为仪表盘能够回答的问题。
捕获已处理的错误
从控制器、任务或跨度中向外传播的错误会被自动记录。captureError() 用于那些不会传播的错误——任何您已捕获并处理、但仍希望它在仪表盘中可见的错误:
该错误会附加到当前追踪上,可选的标签也随之记录;如果启用了 sourceContext,它还会获得与其他被捕获错误相同的源代码上下文处理。
请求作用域属性
setAttribute(key, value) 和 getAttribute(key) 读写追踪自身的上下文存储——这些值在请求存续期间一直存在,可从下游任何位置读取,而不必把它们层层穿透每个函数签名:
getAttribute() 对从未设置过的键返回 undefined。两者在被追踪上下文之外调用时都会抛出异常。
这个存储与追踪 ID 所在的是同一个,因此 getAttribute(traceIdKey) 可以取回当前的追踪 ID——用于与外部系统关联,或把它传播到另一个服务。currentTraceId() 是这一查询的简写形式,但有一个刻意的变化:在被追踪上下文之外它返回 null 而不是抛出异常,因为读取追踪 ID 以便向下游转发,恰恰是那种在还没有追踪时也完全可能合理发生的调用。如果在您的代码中这种情况可能出现,请在设置请求头之前先对 null 做判断。
要为这个存储添加类型,请把它的形状作为 TracerService 的第一个类型参数传入;之后键和值都会依据它进行校验,包括嵌套路径:
info 提示
ObserveModule同样导出了追踪上下文所在的AsyncLocalStorage实例。setAttribute()/getAttribute()是访问它的受支持方式;只有当您需要它们未暴露的能力时,才直接注入该存储。如果您已经在使用 异步本地存储 配方中描述的模式,这个存储可以取代您手工实现的那一个。
自定义指标
有三种指标类型可用,每种都按名称创建(如果名称已存在则取回)。它们上报到仪表盘的自定义部分,并且可以像任何内置指标一样对其设置告警。
与上述方法不同,指标不与追踪绑定,因此可以从任何地方上报——包括启动和关闭代码、onModuleInit() 钩子以及定时任务。
调用 counter('orders.placed') 两次会返回同一个实例,因此无需在字段中保存引用——不过在热路径上保存引用开销更低。在后续调用中传入属性会就地更新现有指标的描述和标签。

一个已声明但从未上报的指标在仪表盘中显示为"未知"而不是 0。这是一种真实状态,而不是数据缺失:"我们从未收到过这个指标的数据"和"这个指标当前为零"是两个不同的事实,把后者当成前者展示会掩盖一次失败的部署。

