读 observability 源码树:从 RequestStage 到 exporter#

这章解决什么问题#

代码导读前面已经教读者如何从入口读到 runtime、如何顺着 protocol 和 io_struct.py 看对象形状、如何用 bench_one_batch.py 当显微镜。但整本书后半程已经引入了非常多观测与证据相关的能力:

  • RequestStage / ReqTimeStats
  • metrics collector
  • request logger
  • request metrics exporter
  • watchdog / health check

如果代码导读不把这些源码树重新收一遍,前面的 observability 章节就更像“功能说明”,而不是一条可回到源码的阅读路径。

这一章就是把 observability 源码树补进代码导读。

为什么这层值得专门成章#

因为在复杂 runtime 里,观测代码并不是边角料。很多时候,它才是最能揭示系统边界与作者意图的地方。比如:

  • 哪些阶段被正式命名为 RequestStage
  • 哪些统计被认为值得长期导出
  • 哪些字段被认为值得落盘

这些都不是“顺手打几个日志”能表达的。

一张图:observability 源码树本身也有稳定层次#

这张图解决的理解障碍是:很多读者看到 observability/ 会只想到 metrics,而不是一棵更完整的证据树。

flowchart TD
    Obs["observability source tree"] --> Time["req_time_stats.py / RequestStage"]
    Obs --> Metrics["metrics_collector.py / scheduler metrics"]
    Obs --> Trace["trace.py / tracing context"]
    Obs --> Log["request_logger.py"]
    Obs --> Export["request_metrics_exporter.py"]

图比纯文字多解释的一点是:observability 源码树不是单文件功能,而是一组彼此衔接的证据层。

为什么应该先读 req_time_stats.py#

因为它几乎是整棵树的“时间语义中枢”。前面维护章节已经反复回扣过 RequestStageReqTimeStats,而如果你要真正从源码层理解 observability,最稳的入口就是:

  • 哪些阶段被定义
  • 哪些 setter 在什么时候被调用
  • 哪些阶段会同时进入 metrics 与 trace

一旦这层搞清楚,后面的 metrics、trace、request logger 都更容易定位在整条请求时间线里的位置。

metrics_collector.py 适合用来读“系统作者认为哪些东西值得长期量化”#

metrics collector 的价值,不只是会导出 Prometheus 指标,而是它在替作者说:

  • 哪些数值得长期看
  • 哪些队列 / routing key / request 数量值得聚合
  • 哪些 label 被视为稳定维度

也就是说,它对“什么算重要运行时事实”做了很强的价值选择。这非常适合技术书做源码回扣。

request_logger.pyrequest_metrics_exporter.py 应该配对读#

如果只读 logger,你会以为系统主要在做人类可读的请求记录;如果只读 exporter,你会以为系统主要在做结构化落盘。更稳的读法是把它们对照起来:

  • 一个更偏值班和现场阅读
  • 一个更偏后续离线分析与批量归档

这种对照阅读特别有价值,因为它让“证据链分层”不再只是概念,而能直接落回源码目录。

trace.py 为什么值得最后读#

因为 trace 往往更像一层承接层。你先弄清:

  • RequestStage 的语义
  • metrics 和 logger 的分层

再回来看 trace,会更容易理解它为什么要有 thread context、slice、abort 事件和 root attrs。否则第一次读 trace.py 很容易只看到抽象 tracing plumbing。

一条更稳的 observability 源码阅读顺序#

建议这样读:

  1. req_time_stats.py
  2. metrics_collector.py / scheduler_metrics_mixin.py
  3. request_logger.py
  4. request_metrics_exporter.py
  5. trace.py

这样读的好处是:你先有时间语义,再有聚合语义,再看日志与落盘,最后才看 tracing plumbing。

这条阅读路径为什么能和整本书形成回扣#

因为它几乎能把前面的很多章节重新串起来:

  • request lifecycle:解释首尾时间点和 request state
  • runtime architecture:解释这些证据由哪层产出
  • scheduling / execution:解释哪些阶段与 batch/forward 绑定
  • extension/debugging:解释为什么这些 observability 能真正用于现场排障

也就是说,这一章的价值不只是多一个目录说明,而是把前文铺好的 observability 主线拉回源码树。

这一层最容易出现的误判#

1. 把 observability 代码当成外围附属层#

其实它经常最清楚地暴露系统边界与阶段定义。

2. 只看 metrics,不看 RequestStage#

这样会失去很多统一时间语义。

3. 只看 trace,不看 logger/exporter#

这样会错过“证据分层”这件更系统性的设计。

如果你准备从源码侧搞清一条请求的证据链,先怎么走#

建议按这个顺序:

  1. 先看 ReqTimeStats 的 setter 是谁在调
  2. 再看 metrics collector 如何消费这些阶段
  3. 再看 request logger 与 exporter 如何在收尾阶段落证据
  4. 最后再看 trace 如何把这些事件组织成跨进程视图

小结#

这一章真正想补齐的,是代码导读对 observability 源码树的正式入口:

  • observability 不是单个目录
  • 它是一棵从阶段语义、到聚合、到日志、到落盘、再到 tracing 的证据树
  • 只有把这棵树读清,前面的维护章节才真正有“回到源码”的抓手

到这里,代码导读就不只覆盖请求和执行主线,也开始覆盖整本书后半程最重要的证据树。