在编译时更改应用程序日志级别是否可行?

9

我希望在编译调试或发行版本时,不依赖于运行时的环境变量,并完全剥离非错误日志消息。

是否可以通过Cargo.toml或通过cargo/rustc命令行参数改变应用程序的日志级别?


“with non-error log messages stripped out completely” — 所以完全不可能选择查看“信息”级别的消息,对吗? - Shepmaster
是的,没错。假设在运行时不需要检查标志并且不需要额外加载str字面量到内存中,那么性能上也会有(非常微小的)提升。 - Peter Hall
1个回答

3

我不相信log crate恰好内置了所请求的功能。

一种静态设置记录级别的方法。如果你使用任何这些Cargo特性编译log crate,则日志级别将在那个点上被限制:

  • release_max_level_off
  • release_max_level_error
  • release_max_level_warn
  • release_max_level_info
  • release_max_level_debug
  • release_max_level_trace

对于非发布版本,您可以省略 release_ 以获得相同的功能。

优化器可能会看到这个静态值并删除不可能的代码。 如果发生这种情况,那么您就可以继续了!

如果您想要“绝对确定”,您可以通过使用Cargo特性来创建自己的条件编译来近似。这里是一个简单的示例,根据特性是否启用,将打印一个值或不打印:
#[cfg(not(feature = "slim"))]
macro_rules! my_info {
    ($x: expr) => { println!("{:?}", $x) }
}

#[cfg(feature = "slim")]
macro_rules! my_info {
    ($x: expr) => { }
}

fn main() {
    my_info!("Hello, world!");
}

这在Cargo.toml中有相应的节:

[features]
slim = []

当您编译/运行程序时,可以选择其中的功能:
$ cargo run
     Running `target/debug/log`
"Hello, world!"
$ cargo run --features=slim
     Running `target/debug/log`
$ 

然后只需将记录器宏包装在自己的有条件编译的宏中即可:

#[cfg(not(feature = "slim"))]
macro_rules! my_info {
    ($($arg: tt)*) => { info!($($arg)*) }
}

#[cfg(feature = "slim")]
macro_rules! my_info {
    ($($arg: tt)*) => { }
}

运行产生以下结果:
$ RUST_LOG=info cargo run
     Running `target/debug/log`
INFO:log: Hello, world!
$ RUST_LOG=info cargo run --features=slim
     Running `target/debug/log`
$

就编辑而言,我不同意这样做。当出现故障时,您最希望能够记录某些内容。在大多数情况下,我认为检查布尔值的成本不足以保证这一点。我还怀疑,在大多数情况下,您不会有几兆字节的文本。

总会有例外情况 - 也许您需要在紧密循环中记录某些内容,或者您必须编译以适应具有有限空间的微控制器。

请注意,我没有尝试将剥离日志消息与“发布”构建的概念耦合在一起。我保证,有时您会希望使用这些消息进行发布构建,因此最好使这两个想法正交。


谢谢。我同意不希望在紧急生产情况下阻止记录。但是当我想要快速打开/关闭特定日志消息时,对于一个正在调试的程序而言有些不太方便。 - Peter Hall
@PeterHall 这个问题可以用一种非常不同的方式解决。查看 env_logger 的文档(http://rust-lang-nursery.github.io/log/env_logger/),你会发现你可以为不同的模块启用不同的日志级别(`RUST_LOG=module1=level,module2=level`),这样你就可以为你感兴趣的一个模块启用 info 日志,甚至是特定的打印!我还更新了答案,加入了我在源代码挖掘中发现的一些东西,这可能已经足够好了。 - Shepmaster
但是...如果我同时运行两个应用程序,我能否在一个应用程序中启用模块的日志记录而不在另一个应用程序中启用它? - Peter Hall
@PeterHall 是的。每次启动应用程序时,您只需设置环境变量 — RUST_LOG=my_module=info ./application1; RUST_LOG=my_module=error ./application2。日志模块/级别设置是每个运行实例的。 - Shepmaster
2
我想指出的是,至少要确保 DEBUG 日志永远不会进入发布二进制文件,这是非常普遍的。大多数日志记录的问题在于需要大量代码进行格式化,虽然通常情况下这些代码不是动态执行的,但它仍然影响优化器所做的决策。日志记录的存在可能会抑制内联、寄存器提升等操作。 - Matthieu M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接