tracing 源码解析
tracing 仓库里的 crate 各自发版、各自打 tag,这一卷的四个主角也就各有各的 tag,每个 crate 都对着自己的 tag 读,源码链接和行号也从各自的 tag 取:
| crate | 版本 | tag | commit | 日期 |
|---|---|---|---|---|
| tracing | 0.1.44 | tracing-0.1.44 | 2d55f6fa | 2025-12-18 |
| tracing-core | 0.1.36 | tracing-core-0.1.36 | 10a9e838 | 2025-12-18 |
| tracing-attributes | 0.1.31 | tracing-attributes-0.1.31 | 55086231 | 2025-11-26 |
| tracing-subscriber | 0.3.23 | tracing-subscriber-0.3.23 | 54ede4d5 | 2026-03-13 |
另有两个 crate 只在一两节出现:tracing-log 0.2.0(tag tracing-log-0.2.0)讲 log 互通,tracing-appender 0.2.5(tag tracing-appender-0.2.5)出现在常见坑里。为什么不能只用一个 tag,见怎么读这一卷。
tracing 由 Tokio 项目维护,但不依赖 tokio。异步那一章讲 Instrumented 怎么在每次 poll 时进出 span,poll 本身链回 tokio 卷;tower-http 的 TraceLayer 在 axum 卷讲过,这里只链过去。
tracing 做的事分成两件,全卷沿这两条线展开:
- 事件主线(每次
info!):宏在调用点展开成一个static的调用点和一段判断,依次过四道门:编译期的STATIC_MAX_LEVEL、全局的LevelFilter::current()、调用点缓存的Interest、当前 subscriber 的enabled。都通过才构造字段、调用Event::dispatch,tracing-subscriber 的Layered把事件交给每个Layer::on_event,fmt::Layer把它格式化成一行写出去。 - span 主线(一个 span 的一生):
info_span!过同样的门,subscriber 的new_span分配一个span::Id;enter把它压进当前线程的 span 栈,守卫 drop 时出栈;Span的 clone 和 drop 增减引用计数,归零时try_close,所有 layer 的on_close跑完才释放 span 的数据。
flowchart TB intro[00 导读] --> overview[01 全景] overview --> core[02 tracing-core] core --> facade[03 tracing 门面] facade --> attrs["04 #[instrument]"] facade --> sub[05 tracing-subscriber] attrs --> design[06 设计取舍] sub --> design design --> pit[07 常见坑] pit --> site[08 在本站中] site --> hands[09 动手]
各部分
- 00 导读:锁定的版本,两条主线,阅读路线;仓库里的 crate、feature 和
src/目录。 - 01 全景:tracing 解决什么问题;一个最小程序把两条主线跑一遍。
- 02 tracing-core:本卷重点。
Metadata与Level、调用点与Interest缓存、Dispatch、Subscribertrait、字段、span 与Event的数据。 - 03 tracing 门面:宏展开成什么、级别过滤的几道门、
Span与Entered、Instrument与异步、和log互通。 - 04 #[instrument]:属性宏展开成什么,以及它的参数。
- 05 tracing-subscriber:
Layer与Layered、Registry、全局与每层过滤、EnvFilter、fmt、reload。 - 06 设计取舍:把各章的取舍汇总到一起。
- 07 常见坑:用报错原文或现象做标题,讲它在源码里怎么产生。
- 08 在本站中:本站(开源)代码里怎么装 subscriber、怎么用
#[instrument]。 - 09 动手:不用 tracing,从零写一个带调用点缓存的最小日志门面。
从「导读」开始。只想会用 tracing 的读者,读 01 全景、03 tracing 门面、04 #[instrument]、05 里的 fmt 和 EnvFilter,以及常见坑;想读懂实现的,按顺序读,02 是全卷的重点:两条主线上的每一步最后都落到 tracing-core 的类型上。
💬 关联讨论
发起讨论加载中...