Difference Between CAPTURE and SHOW Filters in tui-logger Smart Widget

The SHOW filter controls which log entries appear in the terminal interface, while the CAPTURE filter determines which log levels are actually recorded by the underlying logger into the circular buffer.

The gin66/tui-logger crate provides Rust applications with a terminal user interface for log management. Its Smart Widget implements dual-layer filtering where SHOW and CAPTURE operate independently—enabling you to record verbose debug logs while displaying only error levels, or vice versa.

What the SHOW Filter Controls

The SHOW filter is a view-only configuration stored in the widget's private LevelConfig (state.config). According to the implementation in src/widget/target.rs, this filter determines which log entries appear in the UI for each target without affecting the global logger configuration.

Key characteristics of the SHOW filter:

  • Storage: Resides in state.config per target via the set method defined in src/config/level_config.rs
  • Key bindings: decreases and increases the shown level (handled by LeftKey and RightKey in src/widget/inner.rs)
  • State variables: Uses opt_selected_visibility_less and opt_selected_visibility_more to track pending changes
  • Effect: Only changes what is currently rendered; past entries remain in the buffer unchanged
  • Visibility: Targets set to LevelFilter::Off are hidden when hide_target is toggled via the SPACE key

What the CAPTURE Filter Controls

The CAPTURE filter determines which log events are actually recorded by the logger. Unlike SHOW, this affects the global logger state stored in TUI_LOGGER.inner and impacts future log events.

Key characteristics of the CAPTURE filter:

  • Storage: Lives in the global logger and updated via set_level_for_target calls
  • Key bindings: - decreases and + increases the captured level (handled by MinusKey and PlusKey in src/widget/inner.rs)
  • State variables: Uses opt_selected_recording_less and opt_selected_recording_more
  • Effect: Only messages meeting the captured level threshold are stored in the circular buffer
  • Persistence: Setting to LevelFilter::Off stops new events from recording, but existing buffered entries may still appear in the UI

Implementation Details in Source Code

The separation of concerns is enforced across multiple source files in the gin66/tui-logger repository:

src/widget/target.rs calculates available filter levels using advance_levelfilter:

// SHOW filter preparation
let (more, less) = if let Some(levelfilter) = state.config.get(t) {
    advance_levelfilter(levelfilter)
} else {
    (None, None)
};
state.opt_selected_visibility_less = less;
state.opt_selected_visibility_more = more;

src/widget/inner.rs contains the TuiWidgetInnerState::transition method that processes key events:

SHOW filter adjustments update the widget configuration:

LeftKey => {
    if let Some(selected_target) = self.opt_selected_target.take() {
        if let Some(selected_visibility_less) = self.opt_selected_visibility_less.take() {
            self.config.set(&selected_target, selected_visibility_less);
        }
    }
}
RightKey => {
    if let Some(selected_target) = self.opt_selected_target.take() {
        if let Some(selected_visibility_more) = self.opt_selected_visibility_more.take() {
            self.config.set(&selected_target, selected_visibility_more);
        }
    }
}

CAPTURE filter adjustments modify the global logger:

MinusKey => {
    if let Some(selected_target) = self.opt_selected_target.take() {
        if let Some(selected_recording_less) = self.opt_selected_recording_less.take() {
            set_level_for_target(&selected_target, selected_recording_less);
        }
    }
}
PlusKey => {
    if let Some(selected_target) = self.opt_selected_target.take() {
        if let Some(selected_recording_more) = self.opt_selected_recording_more.take() {
            set_level_for_target(&selected_target, selected_recording_more);
        }
    }
}

Key Differences Between SHOW and CAPTURE

Storage Location

  • SHOW: Stored in state.config (widget-only) within LevelConfig
  • CAPTURE: Stored in TUI_LOGGER.inner (global logger state)

Key Bindings

  • SHOW: Adjusted with and keys
  • CAPTURE: Adjusted with - and + keys

Effect on Log History

  • SHOW: Changes current display only; buffered entries persist unchanged
  • CAPTURE: Affects future log recording; determines what enters the circular buffer

Target Visibility

  • SHOW: Controls immediate visibility in the UI; hidden targets can be toggled with SPACE
  • CAPTURE: Controls data collection; OFF stops recording but existing data may remain visible

Programmatic Filter Configuration

To adjust filters programmatically rather than through key bindings, use TuiWidgetState and TuiWidgetEvent:

use tui_logger::{TuiWidgetState, TuiWidgetEvent};

let state = TuiWidgetState::new()
    .set_default_display_level(log::LevelFilter::Trace);

// Decrease shown level (SHOW filter)
state.transition(TuiWidgetEvent::LeftKey);

// Decrease captured level (CAPTURE filter)  
state.transition(TuiWidgetEvent::MinusKey);

For direct CAPTURE filter manipulation without the widget state machine:

// Set capture level for specific target
set_level_for_target("my_target", log::LevelFilter::Debug);

Documentation for these key commands appears in src/lib.rs (lines 71-84) with references to CAPTURED and SHOWN filters.

Summary

  • SHOW filters control UI visibility and live in state.config, modified by ←/→ keys via opt_selected_visibility_less/more
  • CAPTURE filters control log recording and live in the global logger, modified by -/+ keys via opt_selected_recording_less/more
  • Implementation spans src/widget/target.rs, src/widget/inner.rs, and src/config/level_config.rs
  • Both filters can be adjusted programmatically via TuiWidgetState::transition or set_level_for_target

Frequently Asked Questions

Can I set different levels for CAPTURE and SHOW on the same target?

Yes. The filters operate independently. You can set CAPTURE to Trace to record everything while setting SHOW to Error to display only critical messages, enabling detailed debugging without UI clutter.

Why do I still see logs from a target after setting CAPTURE to OFF?

Setting CAPTURE to LevelFilter::Off stops new events from being recorded, but existing entries in the circular buffer remain visible until cleared. The SHOW filter controls visibility of buffered entries, so you must also set SHOW to Off or clear the buffer to hide existing logs.

How do I persist filter settings between application restarts?

The tui-logger crate does not persist filter settings automatically. You must serialize state.config for SHOW filters and replay set_level_for_target calls for CAPTURE filters during application startup, or store these values in your application's configuration file.

Where are the key bindings documented in the source code?

Key bindings are documented in src/lib.rs (lines 71-84) with explicit references to CAPTURED and SHOWN filters, and implemented in src/widget/inner.rs within the TuiWidgetInnerState::transition method that handles LeftKey, RightKey, MinusKey, and PlusKey events.

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 →