eyre 的 span trace 如何启用?
解读
在国内 Rust 后端或中间件面试中,“如何拿到报错时的完整调用链” 是高频考点。eyre 作为社区推荐的错误处理库,默认只打印单层错误;若想输出类似 Java 堆栈的 span trace,必须显式启用 spantrace 特性并配合 tracing 生态。面试官想确认两点:
- 你知道 eyre 与 anyhow 的差异(可扩展性 + span trace)。
- 你能在真实工程里把“编译期开关 + 运行期订阅”两步都踩对,而不是只说“加 feature”。
知识点
- eyre 的 feature flag 体系:
spantrace—— 编译期打开后,eyre::Report 才会在内部记录tracing::Span回溯。auto-install—— 自动调用set_hook,适合 bin crate;lib crate 建议手动 install。
- tracing-subscriber 注册:
必须启用env-filter+fmt并设置RUST_LIB_BACKTRACE=1或RUST_BACKTRACE=1,否则即使收集到 span trace 也不会渲染。 - 与 anyhow 的对比:
anyhow 无 span trace 能力;eyre 通过EyreHandlertrait 允许自定义上下文,因此更适合观测型系统。 - 国内生产环境注意:
日志侧通常接 Loki/ELK,需把 span trace 格式化成 JSON;记得在.cargo/config.toml里给调试版加rustflags = ["--cfg=tracing_unstable"],否则tracing 0.1.x在旧编译器下会丢字段。
答案
分三步:
-
Cargo.toml 打开特性
[dependencies] eyre = { version = "0.6", features = ["spantrace", "auto-install"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }如果是 lib,去掉
auto-install,在初始化函数里手动调用
eyre::set_hook(Box::new(eyre::DefaultHandler::default_with(spantrace)))。 -
main.rs 启动时注册 subscriber
use tracing_subscriber::prelude::*; fn main() -> eyre::Result<()> { tracing_subscriber::registry() .with(tracing_subscriber::fmt::layer()) .with(tracing_subscriber::EnvFilter::from_default_env()) .init(); // 触发错误观察效果 run()?; Ok(()) } -
运行前加环境变量
RUST_BACKTRACE=1 cargo run当错误发生时会同时打印 两层信息:
Error:行开始的标准错误链;Span backtrace:行开始的 span 层级,展示#[instrument]的函数调用顺序。
至此 span trace 启用完成。
拓展思考
- 性能权衡:
span trace 记录的是tracing::Span引用,无 alloc,但每一次with_span都会走原子计数;对热路径(如 100 Mops 的网关)应使用tracing::Level::ERROR级别做条件采样,避免开销。 - 与
color-eyre混用:
color-eyre已内置 spantrace,直接依赖它即可省去手动set_hook;但注意其默认主题带颜色,国内阿里/腾讯生产日志收集器会转义 ANSI 码,需加COLOR_BT=never环境变量关闭。 - 错误上报链路:
在 Sentry 集成场景,可把eyre::Report的 span trace 序列化成 JSON,放入extra字段;结合tracing-error的ErrorLayer,能把同一 TraceId 下的所有 span 统一上报,方便排查微服务雪崩。