env_logger:Rust日志,一个环境变量就够了

env_logger 在 GitHub 上拿到了 1,048 Star。

写 Rust 程序的人基本都知道 log 这个 crate。它定义了 trace、debug、info、warn、error 五个日志级别和一套宏,几乎所有 Rust 库都用它输出日志。但 log 只负责定义接口——日志最终写到哪、怎么写、写不写,它一概不管。

env_logger 就是那个把日志"落地"的实现。它的设计思路很直接:用环境变量控制一切。不用写配置文件,不用在代码里硬编码日志级别,部署的时候改一下 RUST_LOG 就行。

正文顶部截图

1、怎么用

Cargo.toml 里加上两个 crate:

[dependencies]
log = "0.4"
env_logger = "0.11"

main 函数最开头调一次 env_logger::init(),然后所有 log::info!()log::debug!() 宏就能正常输出了:

fn main() {
    env_logger::init();
    log::info!("程序启动了");
}

启动时设好环境变量:

RUST_LOG=info ./target/debug/my_app

终端上会出现带时间戳和模块名的日志行,格式大概是这样:

[2024-01-15T08:30:00Z INFO  my_app] 程序启动了

控制粒度可以精确到模块。只想看 db 模块的 debug 日志,就写 RUST_LOG=db=debug。同时看多个模块用逗号分隔:RUST_LOG=db=debug,api=trace。调试完了关掉所有日志,直接设 RUST_LOG=off

日志级别大小写不敏感,infoINFO 都行。官方推荐统一用小写。

2、不靠环境变量也能配置

有时候不想通过环境变量控制日志——比如日志目标要写到 stdout 而不是默认的 stderr,或者格式要跟默认不一样。Builder 模式覆盖了这些场景:

env_logger::Builder::from_default_env()
    .target(env_logger::Target::Stdout)
    .init();

关于默认输出格式,官方文档交代得很清楚:在 0.x 大版本期间,格式随时可能变。如果你的程序依赖日志输出的具体格式做解析或监控,要自己写自定义格式。env_logger 不承诺向后兼容的格式稳定性。

README区域截图

3、测试里也能用

Rust 的单元测试默认并发执行,而且 cargo test 会吞掉标准输出。想在测试里看到日志,分两步。

第 1 步,在每个需要输出日志的测试函数里调一次初始化:

fn init() {
    let _ = env_logger::builder().is_test(true).try_init();
}

第 2 步,用 RUST_LOG 环境变量指定要看哪些模块的日志。

需要注意,并行测试场景下,多个测试的日志会交错在一起。两个办法解决:设 RUST_TEST_THREADS=1 串行跑全部测试,或者用 RUST_LOG=my_lib=info cargo test 测试函数名 只跑一个。

4、适合谁用

  • 写 Rust CLI 工具或后端服务,不想在日志配置上花太多时间
  • 刚学 Rust,需要在项目里看到代码执行到哪了
  • 代码里已经用了 log 宏,缺一个本地输出的实现

env_logger 不往远端发日志、不做结构化输出、不搞日志聚合。它只做一件事:读 RUST_LOG 环境变量,按规则把日志写到终端。对于大多数命令行工具和中小型服务来说,这就够了。

往远端发日志、不做结构化输出、不搞日志聚合。它只做一件事:读 RUST_LOG 环境变量,按规则把日志写到终端。对于大多数命令行工具和中小型服务来说,这就够了。

更多推荐