Rust in Everything
基于 tracing 0.1.44

动手

前面各部分是读 tracing 的源码,这一部分反过来:不依赖 tracing,自己把事件主线和 span 主线的骨架写一遍。写完再回头看,DefaultCallsite 为什么要两个原子字节、全局 MAX_LEVEL 为什么初值是 OFF、span 栈为什么放在 subscriber 里而不是 tracing 里,都会变成你自己做过的选择。

  1. 从零写一个最小日志门面:约 270 行的库加一个演示程序。event! / span! 宏在调用点放两个 static(元数据和调用点),调用点用一个 AtomicU8 缓存 subscriber 的回答;OnceLock 做只能设一次的全局 dispatcher;一个写 stderr 的 subscriber,按 RUST_LOG="info,demo::app=debug" 的规则过滤,用线程局部的栈记当前 span。用 criterion 实测:被 subscriber 拒绝的 debug!,有缓存约 0.44 ns,每次都问约 4.5 ns。最后一张表列出它和 tracing 的差距。
flowchart TB
  macros["event! 与 span!"] --> statics["static 元数据与调用点"]
  statics --> gate2["全局 MAX_LEVEL"]
  gate2 --> cache["调用点的 AtomicU8"]
  cache --> disp["OnceLock:全局 dispatcher"]
  disp --> sub["stderr subscriber"]
  sub --> stack["线程局部 span 栈"]
  cache --> bench["实测:缓存与不缓存"]

💬 关联讨论

发起讨论
加载中...