How to Configure Hot and Main Buffer Depths for High-Throughput Logging in tui-logger
Use set_hot_buffer_depth() and set_buffer_depth() before initializing the logger to resize the circular buffers and prevent message loss during high-volume logging bursts.
The tui-logger crate employs a dual-buffer architecture to separate high-frequency log ingestion from UI rendering. Understanding how to tune the hot buffer and main buffer depths is essential for applications that generate thousands of log events per second without dropping records or blocking the terminal interface.
Understanding the Two-Buffer Architecture
tui-logger isolates logging throughput from UI latency using two distinct circular buffers implemented in src/circular.rs. This design ensures that log macros never block while the UI redraws.
The Hot Buffer
The hot buffer is the write-optimized first stage where log records land immediately when macros like info!() or debug!() execute. It is a short-lived buffer swapped out automatically every 10 milliseconds or when it reaches 50% capacity.
According to src/logger/inner.rs:54-56, the default hot buffer depth is 1,000 entries (hot_depth = 1000). When this buffer fills faster than the background thread can drain it via move_events(), subsequent log calls trigger ExtLogRecord::overrun and drop messages.
The Main Buffer
The main buffer (events in TuiLoggerInner) stores the drained records that widgets actually render. Because this buffer is locked only during UI redraws, it can safely hold a larger history without affecting log-macro latency.
The default main buffer depth is 10,000 entries, also defined in src/logger/inner.rs:54-56. This determines how far back users can scroll through logs before older entries are overwritten.
Configuring Buffer Depths
The public API in src/logger/api.rs exposes two functions to resize these buffers. Both modify the global TUI_LOGGER singleton.
Setting the Hot Buffer Depth
Call set_hot_buffer_depth() to adjust the capacity of the ingestion buffer:
/// Set the depth of the hot buffer in order to avoid message loss.
pub fn set_hot_buffer_depth(depth: usize) {
TUI_LOGGER.inner.lock().hot_depth = depth;
}
Source: src/logger/api.rs:63-66
This updates the hot_depth field inside TuiLoggerInner. The change takes effect lazily: the next time move_events() executes, it creates a new CircularBuffer with the requested capacity. You can invoke this at any time, including during runtime spikes, though the resize only applies after the current hot buffer swaps out.
Setting the Main Buffer Depth
Call set_buffer_depth() to resize the history buffer that feeds the UI:
/// Set the depth of the circular buffer (main buffer) in order to avoid message loss.
pub fn set_buffer_depth(depth: usize) {
TUI_LOGGER.inner.lock().events = CircularBuffer::new(depth);
}
Source: src/logger/api.rs:69-73
This immediately replaces TuiLoggerInner.events with a fresh CircularBuffer, discarding all existing log entries. Because the main buffer is the direct source for TUI widgets, invoke this before starting the UI or when you intentionally want to reset history.
High-Throughput Configuration Examples
Basic Pre-Initialization Setup
Configure both buffers before calling init_logger() to ensure the application starts with sufficient capacity:
use tui_logger::{init_logger, set_default_level, set_hot_buffer_depth, set_buffer_depth};
use log::LevelFilter;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Increase hot buffer to 5,000 entries for high-frequency bursts
set_hot_buffer_depth(5_000);
// Increase main buffer to 20,000 entries for extended scroll-back
set_buffer_depth(20_000);
// Initialize after configuring sizes
init_logger(LevelFilter::Trace)?;
set_default_level(LevelFilter::Trace);
// Application logic...
Ok(())
}
Runtime Hot Buffer Adjustment
Increase the hot buffer dynamically when detecting a logging spike, such as during batch processing:
use std::thread;
use std::time::Duration;
use tui_logger::set_hot_buffer_depth;
use log::info;
fn handle_burst() {
// Double capacity before the burst
set_hot_buffer_depth(10_000);
for i in 0..5_000 {
info!("Processing batch item {}", i);
}
// Buffer automatically drains to main buffer every 10ms
}
The resize applies after the next automatic swap cycle (10ms max delay).
Resetting Main Buffer During Pauses
When you need to expand history capacity without restarting the application, pause UI updates to avoid reading during the reset:
use tui_logger::set_buffer_depth;
fn clear_and_resize_history() {
// Stop UI updates or ensure no render loop is active
set_buffer_depth(30_000); // New size, previous history cleared
// Resume UI with fresh, larger buffer
}
Why Buffer Depth Matters for Performance
In high-throughput scenarios, the default 1,000-entry hot buffer can saturate within milliseconds under heavy log crate usage. When the hot buffer overflows before move_events() drains it, tui-logger increments overrun counters and drops records to maintain UI responsiveness.
Expanding the hot buffer depth reduces the probability of message loss during transient bursts, while a larger main buffer depth prevents the UI from discarding historical context in long-running services. Both buffers rely on the lock-free circular buffer implementation in src/circular.rs to minimize contention between the logging thread and the rendering thread.
Summary
- Hot buffer (default 1,000): Fast ingestion path; resize with
set_hot_buffer_depth()to prevent dropped messages during bursts. - Main buffer (default 10,000): UI history storage; resize with
set_buffer_depth()which clears existing logs. - Timing: Configure sizes before
init_logger()for consistent startup, or adjust the hot buffer at runtime for reactive scaling. - Implementation: Both buffers use
CircularBufferfromsrc/circular.rs, with defaults defined insrc/logger/inner.rs:54-56.
Frequently Asked Questions
Can I change buffer sizes after initializing the logger?
Yes. set_hot_buffer_depth() can be called at any time; the new size takes effect when the current hot buffer swaps out (within 10ms or at 50% fill). However, set_buffer_depth() immediately clears the main buffer history, so it is safest to call when the UI is paused or during startup.
What happens if the hot buffer fills up before it can swap?
tui-logger detects the overflow condition and marks subsequent records with ExtLogRecord::overrun. These messages are dropped to prevent blocking the logging thread, and the overrun flag indicates data loss in the UI.
Where are the default buffer sizes defined in the source code?
The static defaults (hot_depth = 1000 and main buffer size of 10,000) are initialized in src/logger/inner.rs at lines 54-56 within the TuiLoggerInner struct. The actual circular buffer implementation resides in src/circular.rs.
Is there a performance penalty for setting very large buffer depths?
The hot buffer resize only allocates on the next swap cycle, so it does not block logging threads. The main buffer allocates immediately when set_buffer_depth() is called. While larger buffers consume more heap memory, the circular buffer design in src/circular.rs maintains O(1) insertion and removal regardless of capacity, preserving UI frame rates even with deep history.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →