How tui-logger Handles Lost Messages When the Circular Buffer Overflows
tui-logger detects buffer overflows by comparing total event pushes against actual stored elements in src/logger/inner.rs, then injects a synthetic ExtLogRecord::overrun warning to report exactly how many messages were discarded.
The gin66/tui-logger crate provides a robust logging solution for terminal user interfaces using a dual-buffer architecture. When the internal circular buffer reaches capacity, the library explicitly reports message loss through structured warning entries rather than silently dropping data.
Two-Stage Buffer Architecture
tui-logger implements a two-stage buffering strategy that separates log ingestion from UI rendering:
- Hot buffer: A
CircularBuffer<ExtLogRecord>defined insrc/circular.rsand re-exported insrc/lib.rsthat receives every log entry via theraw_logmethod - Main buffer: A secondary
CircularBuffer<ExtLogRecord>that the terminal interface reads from
When the hot buffer fills to capacity, the move_events function transfers records to the main buffer. This design allows high-throughput logging without blocking the UI thread.
Detecting Buffer Overflows
The overflow detection logic resides in src/logger/inner.rs within the move_events implementation. During transfer, the code retrieves two key metrics from the hot buffer:
total:received_events.total_elements()— The cumulative count of all push operations, including those that overwrote existing entrieselements:received_events.len()— The count of distinct records currently stored in the buffer
When total > elements, the circular buffer has overwritten older records, indicating message loss.
if total > elements {
// Too many events received, so some have been lost
let new_log_entry =
ExtLogRecord::overrun(reversed[reversed.len() - 1].timestamp, total, elements);
reversed.push(new_log_entry);
}
Generating the Overrun Warning
When overflow is detected, tui-logger creates a synthetic warning record using the overrun helper defined in src/circular.rs. This method constructs an ExtLogRecord with level Warn and target "TuiLogger":
fn overrun(timestamp: DateTime<Local>, total: usize, elements: usize) -> Self {
ExtLogRecord {
timestamp,
level: Level::Warn,
target: "TuiLogger".to_string(),
file: None,
module_path: None,
line: None,
msg: format!(
"There have been {} events lost, {} recorded out of {}",
total - elements,
elements,
total
),
}
}
The warning message explicitly states how many events were lost (total - elements), how many were preserved (elements), and the total number generated (total).
Behavior and Consequences
The overrun handling mechanism provides several important guarantees:
- Visible alerts: The warning appears in the TUI as a standard log line with level Warn, ensuring users immediately see data loss occurred
- Accurate statistics: The
total_eventscounter increments bytotal, maintaining correct metrics even during overflow - Graceful degradation: The logger never panics or crashes; it continues operating by discarding oldest messages while notifying the user
Configuration options in src/logger/api.rs allow tuning buffer depths via TuiLoggerBuilder methods like hot_depth() to minimize overflow frequency.
Practical Example
To observe the overflow behavior, configure a small hot buffer and generate excess log messages:
use tui_logger::{TuiLogger, TuiLoggerLevelOutput, TuiLoggerBuilder};
fn main() {
// Initialize logger with minimal hot buffer to force overflow
TuiLoggerBuilder::default()
.hot_depth(3) // Only retain 3 recent events in hot buffer
.build()
.unwrap();
// Emit more messages than the buffer can hold
for i in 0..10 {
log::info!("message {}", i);
}
// Force transfer to trigger overflow detection
TUI_LOGGER.move_events();
}
This produces output similar to:
WARN TuiLogger There have been 7 events lost, 3 recorded out of 10
INFO mycrate message 7
INFO mycrate message 8
INFO mycrate message 9
The warning clearly indicates that messages 0 through 6 were lost due to buffer constraints.
Summary
- tui-logger uses two circular buffers (hot and main) to manage log flow between producers and the UI
- Overflow detection occurs in
src/logger/inner.rsby comparingtotal_elements()againstlen() - The
ExtLogRecord::overrunmethod insrc/circular.rsgenerates synthetic warnings with precise loss metrics - Lost message reports include the count lost, recorded, and total generated for complete transparency
- The system maintains accurate statistics and continues operating without panics during overflow conditions
Frequently Asked Questions
How does tui-logger detect that messages have been lost?
tui-logger detects lost messages in src/logger/inner.rs by comparing the return value of received_events.total_elements() (total pushes) against received_events.len() (current stored count). If the total exceeds the current length, the circular buffer has overwritten older entries, triggering warning generation.
Where is the overflow warning message formatted?
The warning message formatting resides in src/circular.rs within the ExtLogRecord::overrun method. This associated function constructs a complete log entry structure with level Warn, target "TuiLogger", and a detailed message string explaining exactly how many events were lost versus recorded.
Does tui-logger panic when the circular buffer overflows?
No. According to the implementation in src/logger/inner.rs, tui-logger handles overflows gracefully by creating a synthetic warning record and continuing operation. The system increments statistics correctly and preserves the most recent messages while discarding older ones without crashing.
How can I prevent message loss in tui-logger?
Configure larger buffer sizes using TuiLoggerBuilder::default().hot_depth(n) as defined in src/logger/api.rs. Increasing the hot buffer depth reduces the likelihood of overflow during high-throughput logging scenarios, though the overrun warning system ensures you are notified if capacity is exceeded regardless.
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 →