Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to change the log level for an application at compile time?

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?

like image 855
Peter Hall Avatar asked Dec 30 '15 22:12

Peter Hall


People also ask

Can we change log level at runtime?

For each service that you have running in BMC Atrium Discovery, you can dynamically change the log level without having to restart the appliance.

How do you change the log level?

To change log levels as a root user, perform the following: To enable debug logging, run the following command: /subsystem=logging/root-logger=ROOT:change-root-log-level(level=DEBUG) To disable debug logging, run the following command: /subsystem=logging/root-logger=ROOT:change-root-log-level(level=INFO)


1 Answers

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.

like image 144
Shepmaster Avatar answered Oct 28 '22 04:10

Shepmaster