Rust 日志与 tracing
log facade 与 tracing 结构化诊断:跨服务相关字段、层级与生产习惯。
#concept
#growing
#dev
#rust
[!info] related notes
Rust 日志与 tracing
这个概念为什么出现
println! 本身只输出文本,不提供级别过滤与 span 上下文;简单程序可用,结构化诊断需额外机制。
生态常用 log 门面或 tracing 做结构化事件。
[!abstract] 一句话理解 用
tracing(或log+实现)记录带字段的事件与跨度;在二进制入口安装 subscriber;库只打事件不绑死后端。
最小可运行示例
场景:请求处理打结构化事件
添加依赖:cargo add tracing 与 cargo add tracing-subscriber --features json。
use tracing::{info, instrument};
#[instrument]
fn handle_order(order_id: u64) {
info!(status = "paid", "order handled");
}
fn main() {
tracing_subscriber::fmt()
.json()
.with_max_level(tracing::Level::INFO)
.init();
handle_order(42);
}
运行 cargo run 后输出 JSON 事件,包含 INFO 级别、status=paid 和 handle_order span 的 order_id=42;时间戳与目标名称依环境变化。此例固定 INFO,未接入 RUST_LOG。
结合场景再看三个关注点
- 库用 tracing/log,二进制选 subscriber
- 字段结构化 便于检索
- 敏感数据脱敏
核心概念
- level:error/warn/info/debug/trace
- span:请求范围上下文
- tracing span 是进程内上下文;跨服务 trace propagation、采样与 OpenTelemetry exporter 需另外配置,不会自动出现分布式追踪
- instrument 默认记录参数的 Debug 表示,敏感或庞大参数需 skip/skip_all,并显式选择允许的字段
- async 代码不要持有 span.enter() guard 跨 await,应用 Instrument 或 async 函数上的 instrument,避免上下文串到其他任务
- 全局 subscriber 通常只初始化一次;库不安装,测试可使用局部 subscriber。RUST_LOG 需要配置 EnvFilter 及对应 feature
工程实践
- 统一 request_id
- 采样与级别可配置
- JSON 输出对接采集
- 错误带
error=%e或 source 链
本节总结
- 结构化日志/追踪
- 门面与实现分离
- 服务排障基础
自测题
- 库为什么不应初始化 global subscriber?
- span 有什么用?
参考答案
- 应用决定导出与格式。
- 关联一次请求内多个事件的上下文。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| tracing | 生态 | 诊断框架 |
| log | 生态 | 门面 |