← 中文资源

简体中文版本

Tracing 订阅器与 EnvFilter 初始化

初始化 tracing 订阅器:EnvFilter 按模块分级过滤、生产走 JSON 扁平输出开发走彩色美化、instrument 宏自动创建带参 span。

阅读英文原文

示例说明

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");
}