tracing 门面
上一部分的 tracing-core 只定义类型:Metadata、DefaultCallsite、Dispatch、Subscriber、ValueSet。用户写的 info!、info_span!、span.enter()、.instrument(span) 都来自 tracing 这个 crate。它做的事是把这些类型拼起来:宏在每个调用点放好静态数据和判断,Span 记住自己属于哪个 dispatcher,Instrumented 在 poll 前后进出 span,log feature 在没有 subscriber 时把事件转给 log。
五章:
- 宏展开:用
cargo expand看info!("x = {}", x)和info_span!("req", id = 1)展开成什么,每种字段写法变成什么;macros.rs3 342 行里,五个级别宏是逐字相同的五份拷贝,event!里同一段主体写了六遍。 - 级别过滤的几道门:事件主线上的五道门依次是
STATIC_MAX_LEVEL、LevelFilter::current()、调用点的Interest、Subscriber::enabled、event_enabled;前四道挡住的事件不对字段表达式求值;用 criterion 测每道门的开销。 - Span 与 Entered:
Span里的inner是Option,被过滤掉的 span 所有操作都是空操作;enter返回借用 span 的守卫,entered返回拥有 span 的守卫;Clone、Drop对应 subscriber 的引用计数。 - Instrument 与异步:
Instrumented<F>每次poll前进入 span、返回后退出,Drop时也进入一次;为什么不能跨.await持有Entered;WithDispatch把 dispatcher 带进别的任务。 - 和 log 互通:两个方向,tracing 的事件经
logfeature 变成log记录,log的记录经 tracing-log 的LogTracer变成 tracing 事件;两边都开时会不会重复。
flowchart TB user["info! 与 info_span!"] --> exp["宏展开:static 元数据"] exp --> gates["五道门"] gates --> ev["Event::dispatch"] gates --> sp["Span::new"] sp --> ent["enter 与 Entered"] ent --> inst["Instrumented:每次 poll"] ev --> logfeat["log feature:转给 log"]
前两章在事件主线的开头,后两章在 span 主线上,最后一章两条线都碰到。宏展开后调用的类型在 tracing-core 一部分讲过,这里只链过去;#[instrument] 生成的代码在 展开成什么。
💬 关联讨论
发起讨论加载中...