Skip to content

Dynamically change log level after init #228

Description

@hasezoey

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)

Activity

  1. wiz21b commented on Mar 19, 2022

    @wiz21b

    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();
    
  2. morrisonlevi commented on May 23, 2022

    @morrisonlevi

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

  3. hasezoey commented on May 23, 2022

    @hasezoey
    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?

  4. KodrAus commented on May 25, 2022

    @KodrAus
    Collaborator

    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.

  5. epage commented on Nov 10, 2022

    @epage
    Contributor

    btw #113 looks somewhat related

  6. added 2 commits that reference this issue on Oct 14, 2024
  7. yuezk commented on Jan 8, 2025

    @yuezk

    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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions