Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamically change log level after init #228

Open
hasezoey opened this issue Mar 2, 2022 · 6 comments
Open

Dynamically change log level after init #228

hasezoey opened this issue Mar 2, 2022 · 6 comments

Comments

@hasezoey
Copy link

hasezoey commented Mar 2, 2022

Is there currently a way to change the log level after having called init already? If there is currently no way, i would like to request this feature

Use case:
i would like to enable logging as the first thing in my code to have log output (from env, etc) and later after having parsed the cli (like with clap) set the level based on something like verbosity.
also another use case would be to dynamically turn the logging on / off for a specific part (which is probably already covered by #144)

@wiz21b
Copy link

wiz21b commented Mar 19, 2022

I'd like to mention that I have a similar use case. I have tried to disable logging before initializing the builder but it doesn't work. I've also tried to send all the log to a sink target, but it doesn't work either. It seems that the RUST_LOG env. variable takes priority over the settings of the builder...

This is what I do:

log_builder.filter(None, LevelFilter::Error);
log_builder.target(env_logger::Target::Pipe(sink));
log_builder.init();

@morrisonlevi
Copy link

You don't need env_logger to change the log level as the log crate already provides log::set_max_level.

@hasezoey
Copy link
Author

You don't need env_logger to change the log level as the log crate already provides log::set_max_level.

the documentation says Generally, this should only be called by the active logging implementation., is env_logger fine with it being change outside of itself?

@KodrAus
Copy link
Collaborator

KodrAus commented May 25, 2022

I think you might get strange results calling set_max_level directly, since env_logger "compiles" the max level into its filters, those aren't derived on-the-fly from the max level set in log.

@epage
Copy link
Contributor

epage commented Nov 10, 2022

btw #113 looks somewhat related

wfchandler added a commit to oxidecomputer/oxide.rs that referenced this issue Oct 14, 2024
Currently the `--debug` flag does not actually enable debug logging as
intended. We initialize `env_logger` immediately in `main`, then attempt
to change the log filtering level in `NewCli::run` if the `--debug` flag
is passed. In practice this does not work, as `env_logger::builder`
needs `init` to be called to change the global logger. This is not an
option, as we've already called `init`. The internet suggests[0] that
using `log::set_max_level` lets us change the level after `init`, but it
did not work when I tried it out.

Move logger initialization into `NewCli::run` so that we know the
desired log level ahead of calling `init`. This means that items logged
before we initialize the logger will be lost, but in practice we're not
missing anything.

[0] rust-cli/env_logger#228 (comment)
wfchandler added a commit to oxidecomputer/oxide.rs that referenced this issue Oct 14, 2024
Currently the `--debug` flag does not actually enable debug logging as
intended. We initialize `env_logger` immediately in `main`, then attempt
to change the log filtering level in `NewCli::run` if the `--debug` flag
is passed. This does not work, as `env_logger::builder` needs its `init`
method to be called to change the global logger. This is not an option,
as we've already called `env_logger::init`. The internet suggests[0]
that using `log::set_max_level` lets us change the level independently
of logger initialization, but this did not work when I tried it out.

Move logger initialization into `NewCli::run` so that we know the
desired log level ahead of calling `init`. This means that items logged
before we initialize the logger will be lost, but in practice we're not
missing anything.

[0] rust-cli/env_logger#228 (comment)
@yuezk
Copy link

yuezk commented Jan 8, 2025

Below is what I implemented using the log-reload crate. Works perfectly.

logger.rs

use std::sync::OnceLock;

use env_logger::Logger;
use log::{warn, Level};
use log_reload::{ReloadHandle, ReloadLog};

static LOG_HANDLE: OnceLock<ReloadHandle<log_reload::LevelFilter<Logger>>> = OnceLock::new();

pub fn set_max_level(level: Level) -> anyhow::Result<()> {
  let log_handle = LOG_HANDLE.get_or_init(|| {
    // Initialize the env_logger and global max level to trace, the logs will be
    // filtered by the level_filter_logger below
    let logger = env_logger::builder().filter_level(log::LevelFilter::Trace).build();
    log::set_max_level(log::LevelFilter::Trace);

    // Create a new logger that will filter the logs based on the max level
    let level_filter_logger = log_reload::LevelFilter::new(level, logger);

    let reload_log = ReloadLog::new(level_filter_logger);
    let handle = reload_log.handle();

    // Register the logger to be used by the log crate
    if let Err(err) = log::set_boxed_logger(Box::new(reload_log)) {
      warn!("Failed to set the logger: {}", err);
    }

    handle
  });

  // Update the log level
  log_handle
    .modify(|logger| logger.set_level(level))
    .map_err(|e| anyhow::anyhow!(e))
}

Call logger.set_max_level(level) dynamically to change the log level at runtime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants