日志框架
问题
Rust 常用的日志方案有哪些?log 和 tracing 有什么区别?
答案
log:简单日志
log 是 Rust 的日志门面(facade),类似 Java 的 SLF4J。
use log::{info, warn, error, debug, trace};
fn main() {
env_logger::init(); // 初始化后端
info!("服务启动,端口: {}", 8080);
warn!("配置未找到,使用默认值");
error!("数据库连接失败: {}", "timeout");
debug!("请求详情: {:?}", request);
}
tracing:结构化可观测
tracing 是 log 的演进,支持结构化日志 + 分布式追踪,是 async Rust 的首选方案。
use tracing::{info, warn, instrument, span, Level};
use tracing_subscriber;
// #[instrument] 自动创建 span,记录函数参数
#[instrument(skip(password))] // 跳过敏感字段
async fn login(username: &str, password: &str) -> Result<String, Error> {
info!(username, "开始登录");
let user = db::find_user(username).await?;
info!(user_id = user.id, "登录成功");
Ok(user.token)
}
fn main() {
// 初始化订阅者
tracing_subscriber::fmt()
.with_max_level(Level::DEBUG)
.with_target(false)
.json() // JSON 格式输出
.init();
}
log vs tracing
| 特性 | log | tracing |
|---|---|---|
| 结构化日志 | ❌ | ✅ 原生支持 |
| Span(跨度) | ❌ | ✅ 追踪请求链路 |
| async 支持 | 基础 | ✅ 原生支持 |
| 性能 | 快 | 快(零成本 span) |
| 生态 | 成熟 | 快速增长 |
| 推荐场景 | 简单 CLI、库 | Web 服务、微服务 |
选择建议
- 写库:用
log(更轻量,兼容 tracing) - 写应用:用
tracing(功能更强,支持 OpenTelemetry)
常见面试问题
Q1: tracing 的 span 有什么用?
答案:
Span 表示一个逻辑操作的持续时间,可以嵌套形成树形结构。在 async 环境中,span 会跟随 Future 跨线程传播,实现分布式追踪。搭配 tracing-opentelemetry 可将 span 导出到 Jaeger/Zipkin。
Q2: 如何在生产环境配置日志?
答案:
use tracing_subscriber::{fmt, EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
tracing_subscriber::registry()
.with(EnvFilter::from_default_env()) // RUST_LOG 环境变量控制级别
.with(fmt::layer().json()) // JSON 格式
.init();
通过 RUST_LOG=my_app=debug,tower=warn 精细控制各模块日志级别。