示例说明
tracing 的数据面与订阅面分离:宏调用只产生事件,subscriber 决定它们去哪。EnvFilter 让过滤规则由 RUST_LOG 环境变量驱动——运维不改代码就能临时放大某模块的日志级别;默认兜底串声明基础级别与例外。输出格式按环境分流:生产的 JSON 可直接进采集器,开发的彩色输出人类友好。
技术要点
- EnvFilter 环境变量驱动级别调整
- JSON 与 pretty 按环境分流
- instrument 宏自动生成函数 span
代码解读
init_tracing 先解析环境变量失败则用默认指令串(info 级加模块例外);registry 叠加过滤层与格式化层完成装配。process_order 的 instrument 宏把函数变成 span:参数自动进属性、skip 排除大载荷;函数内三级日志演示事件与 span 的嵌套输出。
使用建议
RUST_LOG 指令语法值得团队统一文档化。生产 JSON 层可再叠加时间戳与目标字段。span 数量要有节制防开销累积。
代码示例
use tracing::{debug, error, info, instrument, warn};
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
#[instrument(name = "order_flow", skip(payload))]
fn process_order(order_id: u64, payload: &str) -> u64 {
debug!(bytes = payload.len(), "payload received");
let total = payload.len() as u64 * order_id % 97;
info!(total, "order total computed");
total
}
fn init_tracing() {
let filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("info,order_service=debug"));
let is_prod = std::env::var("APP_ENV")
.map(|v| v == "production")
.unwrap_or(false);
let registry = tracing_subscriber::registry().with(filter);
if is_prod {
registry
.with(fmt::layer().json().flatten_event(true))
.init();
} else {
registry
.with(fmt::layer().pretty().with_target(false))
.init();
}
}
fn main() {
init_tracing();
let span = tracing::info_span!("startup", version = env!("CARGO_PKG_VERSION"));
let _guard = span.enter();
info!("service starting");
warn!("cache warmup skipped");
let total = process_order(42, "line-item;quantity=3");
error!(total, "downstream settlement slow");
drop(_guard);
info!("shutdown complete");
}