How to Configure Log Levels Using Environment Variables with `set_env_filter_from_env` in tui-logger

Call set_env_filter_from_env(None) after initializing the logger to parse the RUST_LOG environment variable and apply standard filter directives to both the circular buffer and the TUI widget.

The tui-logger crate provides a direct path to configure log levels using environment variables with set_env_filter_from_env. This function, found in the gin66/tui-logger repository, integrates with the env-filter crate to parse standard logging directives and apply them instantly to your terminal user interface.

How set_env_filter_from_env Works Internally

The implementation resides in src/logger/api.rs at lines 111-122, where the function signature is defined as:

pub fn set_env_filter_from_env(env_name: Option<&str>)

The Filter Installation Process

When invoked, the function executes four distinct operations to configure the filtering mechanism:

  1. Creates two env_filter::Builder instances. The tui-logger architecture maintains separate filters for the hot-select circular buffer (used for real-time widget display) and the main logger (used for file logging).
  2. Reads the environment variable. Passing None defaults to reading RUST_LOG; passing Some("VAR_NAME") reads your custom variable instead.
  3. Parses the filter string. The syntax follows standard env-filter conventions, such as mycrate=info,othercrate::module=debug,hyper=error.
  4. Installs the filters. The built filter objects populate TUI_LOGGER.hot_select and TUI_LOGGER.inner, immediately affecting which log events appear in the widget.

You can call this function multiple times during runtime to reconfigure filters without restarting the application.

Configuring Log Levels from Environment Variables

Using the Default RUST_LOG Variable

The standard approach uses the conventional RUST_LOG environment variable recognized across the Rust ecosystem:

use tui_logger::{init_logger, set_default_level, set_env_filter_from_env};
use log::LevelFilter;

fn main() {
    // Initialize the logger with maximum verbosity
    init_logger(LevelFilter::Trace).unwrap();
    
    // Set fallback level for targets not specified in the filter
    set_default_level(LevelFilter::Trace);
    
    // Parse RUST_LOG and apply filters
    set_env_filter_from_env(None);
}

Run your application with specific directives:

RUST_LOG="mycrate=debug,othercrate::mod=info" cargo run

The logger will display debug messages from mycrate and info messages from othercrate::mod, while respecting the default Trace level for all other targets.

Specifying a Custom Environment Variable

For applications requiring specific variable names (such as avoiding conflicts with other log configurations), pass the identifier directly:

use tui_logger::{init_logger, set_default_level, set_env_filter_from_env};
use log::LevelFilter;

fn main() {
    init_logger(LevelFilter::Trace).unwrap();
    set_default_level(LevelFilter::Trace);
    
    // Use LOG_FILTER instead of RUST_LOG
    set_env_filter_from_env(Some("LOG_FILTER"));
}

Execute with your custom variable:

LOG_FILTER="tui_logger=warn,example=trace" cargo run

Updating Filters at Runtime

The function supports dynamic reconfiguration without application restarts. This pattern allows you to adjust verbosity during debugging sessions:

use tui_logger::{init_logger, set_default_level, set_env_filter_from_env, move_events};
use log::LevelFilter;

fn main() {
    init_logger(LevelFilter::Trace).unwrap();
    set_default_level(LevelFilter::Trace);
    
    // Initial configuration from environment
    set_env_filter_from_env(None);
    
    // Process events with initial filter...
    move_events();
    
    // Change environment variable programmatically
    std::env::set_var("RUST_LOG", "mycrate=error");
    
    // Re-apply the new configuration
    set_env_filter_from_env(None);
    
    // Subsequent logs now obey the error-only filter
}

Note that move_events() ensures any buffered events are processed before the filter change takes effect.

Integration with the Logger Widget

Complete integration with TuiLoggerWidget follows this pattern, as demonstrated in the crate examples:

use tui_logger::*;
use ratatui::{backend::CrosstermBackend, Terminal, widgets::Block};
use std::io::stdout;
use log::LevelFilter;

fn main() -> std::io::Result<()> {
    // Initialize logger infrastructure
    init_logger(LevelFilter::Trace).unwrap();
    set_default_level(LevelFilter::Trace);
    
    // Apply environment-based filtering
    set_env_filter_from_env(None);

    // Setup terminal backend
    let backend = CrosstermBackend::new(stdout());
    let mut terminal = Terminal::new(backend)?;

    // Render the logger widget
    terminal.draw(|f| {
        let widget = TuiLoggerWidget::default()
            .block(Block::default().title("Demo Logger"));
        f.render_widget(widget, f.size());
    })?;

    Ok(())
}

Test the filtering with:

RUST_LOG="tui_logger=info" cargo run --example demo --features crossterm

Summary

  • set_env_filter_from_env parses environment variables using standard env-filter syntax and applies directives to both the hot-select and main logger instances.
  • Default behavior reads from RUST_LOG when passed None; custom variable names require Some("VAR_NAME").
  • Implementation location is src/logger/api.rs lines 111-122, where the function builds and installs filters into TUI_LOGGER.hot_select and TUI_LOGGER.inner.
  • Runtime updates are supported—call the function again after modifying environment variables to apply new filter configurations without restarting.
  • Test coverage exists in tests/envfilter.rs, demonstrating the parsing logic (using set_env_filter_from_string, which follows identical parsing rules).

Frequently Asked Questions

What filter syntax does the environment variable use?

The function uses standard env-filter syntax as implemented in the env-filter crate. You specify comma-separated directives in the format target=level, where level can be trace, debug, info, warn, or error. For example: myapp=debug,hyper::client=info,warn sets myapp to debug, hyper::client to info, and everything else to warn.

Can I change log levels without restarting my application?

Yes. After modifying the environment variable with std::env::set_var(), call set_env_filter_from_env again with the same arguments. The function rebuilds the filter and immediately updates TUI_LOGGER.hot_select and TUI_LOGGER.inner, applying new levels to subsequent log events dynamically.

Why does set_env_filter_from_env create two filter builders?

The tui-logger architecture maintains two separate filter states: one for the hot-select circular buffer (used for the widget display) and one for the main logger (used for file output and other sinks). Both must be updated simultaneously to ensure consistent filtering behavior across all logging destinations.

How does this function interact with set_default_level?

set_default_level establishes a baseline level filter that applies when no specific directive matches a target. When you call set_env_filter_from_env, it overrides specific targets mentioned in the environment variable while leaving others at the default level. The default level acts as a catch-all for unspecified modules, whereas the env filter provides granular control.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →