9

Rather than rely on environment variables at runtime, I'd like to compile a debug or release version with non-error log messages stripped out completely.

Is it possible to change the log level for an application in the Cargo.toml or via cargo/rustc command line arguments?

Akavall
  • 82,592
  • 51
  • 207
  • 251
Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • *with non-error log messages stripped out completely* — So it would be completely and totally impossible to opt into seeing "info" level messages, correct? – Shepmaster Dec 30 '15 at 23:27
  • Yes, exactly. Presumably there would also be a (very minor) performance improvement in not having to check a flag at runtime, and not having extra `str` literals loaded into memory. – Peter Hall Dec 30 '15 at 23:31

1 Answers1

3

I don't believe that the log crate has exactly the requested functionality built in.

There is a way to statically set the logging level. If you compile the log crate with any of these Cargo features, the log level will be capped at that point:

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

You can drop the release_ off for the same functionality in non-release builds.

It's possible that the optimizer will see this static value and remove code that is impossible. If that happens, then you should be good to go!

If you want to be absolutely certain, you could approximate it by creating your own conditional compilation with Cargo features. Here's a simple example that will print a value or not, depending on whether the feature is enabled:

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

This has a corresponding stanza in Cargo.toml:

[features]
slim = []

And when you compile / run your program, you can pick which features there are:

$ cargo run
     Running `target/debug/log`
"Hello, world!"
$ cargo run --features=slim
     Running `target/debug/log`
$ 

Then it's just a matter of wrapping the logger macros in your own conditionally-compiled macros:

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

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

Running yields:

$ RUST_LOG=info cargo run
     Running `target/debug/log`
INFO:log: Hello, world!
$ RUST_LOG=info cargo run --features=slim
     Running `target/debug/log`
$

For a bit of editorial, I disagree with doing this. When something breaks, that's when you most want the ability to log something. In the majority of cases, I don't believe that the cost of the check of the boolean would be expensive enough to warrant this. I also doubt that you will have megabytes of text in most cases.

There are always exceptions - maybe you need to log something in a tight loop, or you have to compile to fit on a microcontroller with limited space.

Note that I didn't try to couple stripping out the log messages with the concept of a "release" build. I guarantee that there are times you will want a release build with these messages, so it's better to make those two ideas orthogonal.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Thanks. I agree about not wanting to prevent logging to be turned on in an emergency production situation. But it's a little inconvenient when I want to quickly turn on an off specific log messages, for just one program, while I'm debugging it. – Peter Hall Dec 31 '15 at 15:04
  • @PeterHall that's solvable in a *very* different way. Check the [docs for `env_logger`](http://rust-lang-nursery.github.io/log/env_logger/) and you can see you can enable different levels for different modules (`RUST_LOG=module1=level,module2=level`), so you could enable info logging for the one module you are interested in, or even a specific print! I also updated the answer with some more stuff I discovered while source digging, which may be good enough for you. – Shepmaster Dec 31 '15 at 19:42
  • But... If I had two applications running at the same time, could I enable logging for a module in one application without enabling it in the other? – Peter Hall Dec 31 '15 at 20:03
  • @PeterHall yeah. You would just set the environment variable when you start each application — `RUST_LOG=my_module=info ./application1; RUST_LOG=my_module=error ./application2`. The logging module / level settings are per running instance. – Shepmaster Dec 31 '15 at 20:07
  • 2
    I would like to note that it is very common to at the very least ensure that DEBUG logs never make it into a Release binary. The problem of most logging is that a *significant* amount of code is required for formatting, and while this code is not dynamically executed in general, it still factors in the decisions the optimizer takes. The presence of logging may inhibit inlining, promotion to registers, etc... – Matthieu M. Jan 01 '16 at 13:07