Renato Zannon
Renato Zannon

Reputation: 29971

Is there a way to programmatically change the default logging level of the log crate?

I'm developing a project in Rust that is meant to be used by systems administrators, via CLI. In this program, I would like to have lines like these:

warn!("File {} not found, proceeding to next file", file_path);

Which I don't consider errors in the context of the software, but I still would want my users to be aware of.

However, Rust's logging system, by default, only prints messages on the ERROR log level, and the only way I found to change this default is to set the RUST_LOG environment variable - which I don't want my users to have to do. I guess I could create a wrapper script that just sets the variable and execs the program, but I would rather not.

Is there a way to change the default level programmatically, from inside the program?

Upvotes: 12

Views: 9412

Answers (6)

Timmmm
Timmmm

Reputation: 96733

This is the cleanest way I could find:

let env = Env::new().filter_or("FOO_LOG", "info");
Builder::from_env(env).init();

Upvotes: 4

Dmitry
Dmitry

Reputation: 704

If you use env_logger you can do in main something like this:

    env_logger::builder()
        .filter_level(log::LevelFilter::Debug)
        .format_target(false)
        .format_timestamp(None)
        .init();

Upvotes: 13

tworec
tworec

Reputation: 4727

Here's a trick which will make it

if env::var("RUST_LOG").is_err() {
    env::set_var("RUST_LOG", "info")
}
env_logger::init();

Upvotes: 18

Akavall
Akavall

Reputation: 86248

Here is an example of what I think you are looking for:

#[macro_use]
extern crate log;
use log::{LogRecord, LogLevel, LogMetadata, LogLevelFilter, SetLoggerError};

struct SimpleLogger;

impl log::Log for SimpleLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Warn
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            // I can probably change colors here
            println!("{} - {}", record.level(), record.args());
        }
    }
}

pub fn init() -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(LogLevelFilter::Warn);
        Box::new(SimpleLogger)
    })
}

fn main() {

    init(); // probably should do something better here

    info!("I am info");
    warn!("I am warn");
    error!("I am error");
}

Upvotes: 3

Renato Zannon
Renato Zannon

Reputation: 29971

Thanks to Vladimir's answer, I dug on the liblog source, and ended up finding a hacky (and probably racy) way to do it:

fn main() {
    use std::os;
    os::setenv("RUST_LOG", "warn");
}

If this is done before any logging, then the logging system will be set up as if it was set from the outside.

Upvotes: 1

Vladimir Matveev
Vladimir Matveev

Reputation: 127941

No, this is not possible. Just skimming through the code of liblog library you can see that all log level configuration is stored in global variables which are modified only once, using Once primitive, and there is no way to modify this configuration.

Rust logging is very simple; if you want something more sophisticated, you will have to do it yourself. liblog provides an extension point, a trait called Logger, it probably can be used for your purpose.

Upvotes: 5

Related Questions