| Crates.io | tui-logger |
| lib.rs | tui-logger |
| version | 0.18.1 |
| created_at | 2018-05-19 08:31:45.940213+00 |
| updated_at | 2026-01-19 20:53:43.413942+00 |
| description | Logger with smart widget for the `ratatui` crate |
| homepage | |
| repository | https://github.com/gin66/tui-logger |
| max_upload_size | |
| id | 66139 |
| size | 7,025,446 |
tui and ratatui crate
I have stumbled over an excellent AI-generated description of tui-logger, which provides surprisingly deep and (mostly) correct implementation details.
It would have costed me many days to write an equally good description with so many details and diagrams.
This docu can be found here.
tuiThe tui crate has been archived and ratatui has taken over.
In order to avoid supporting compatibility for an inactive crate,
the v0.9.x releases are the last to support tui. In case future bug fixes
are needed, the branch tui_legacy has been created to track changes to 0.9.x releases.
Starting with v0.10 tui-logger is ratatui only.
log crateslog support, providing a Drain to integrate into your slog infrastructuretracing supportSmart widget consists of two widgets. Left is the target selector widget and on the right side the logging messages view scrolling up. The target selector widget can be hidden/shown during runtime via key command. The key command to be provided to the TuiLoggerWidget via transition() function.
The target selector widget looks like this:

It controls:
The two columns have the following meaning:
warn!(target: "demo", "Log message");| KEY | ACTION
|----------|-----------------------------------------------------------|
| h | Toggles target selector widget hidden/visible
| f | Toggle focus on the selected target only
| UP | Select previous target in target selector widget
| DOWN | Select next target in target selector widget
| LEFT | Reduce SHOWN (!) log messages by one level
| RIGHT | Increase SHOWN (!) log messages by one level
| - | Reduce CAPTURED (!) log messages by one level
| + | Increase CAPTURED (!) log messages by one level
| PAGEUP | Enter Page Mode and scroll approx. half page up in log history.
| PAGEDOWN | Only in page mode: scroll 10 events down in log history.
| ESCAPE | Exit page mode and go back to scrolling mode
| SPACE | Toggles hiding of targets, which have logfilter set to off
The mapping of key to action has to be done in the application. The respective TuiWidgetEvent has to be provided to TuiWidgetState::transition().
Remark to the page mode: The timestamp of the event at event history's bottom line is used as reference. This means, changing the filters in the EWIDT/focus from the target selector window should work as expected without jumps in the history. The page next/forward advances as per visibility of the events.
#[macro_use]
extern crate log;
//use tui_logger;
fn main() {
// Early initialization of the logger
// Set max_log_level to Trace
tui_logger::init_logger(log::LevelFilter::Trace).unwrap();
// Set default level for unknown targets to Trace
tui_logger::set_default_level(log::LevelFilter::Trace);
// code....
}
For use of the widget please check examples/demo.rs
Run demo using termion:
cargo run --example demo --features termion
Run demo with crossterm:
cargo run --example demo --features crossterm
Run demo using termion and simple custom formatter in bottom right log widget:
cargo run --example demo --features termion,formatter
tui.logger uses env-filter crate to support configuration by a string or an environment variable.
This is an opt-in by call to one of these two functions.
pub fn set_env_filter_from_string(filterstring: &str) {}
pub fn set_env_filter_from_env(env_name: Option<&str>) {}
Default environment variable name is RUST_LOG.
slog supporttui-logger provides a [TuiSlogDrain] which implements slog::Drain and will route all records
it receives to the tui-logger widget.
Enabled by feature "slog-support"
tracing-subscriber supporttui-logger provides a [TuiTracingSubscriberLayer] which implements
tracing_subscriber::Layer and will collect all events
it receives to the tui-logger widget
Enabled by feature "tracing-support"
#[macro_use]
extern crate log;
//use tui_logger;
use env_logger;
fn main() {
// Early initialization of the logger
let drain = tui_logger::Drain::new();
// instead of tui_logger::init_logger, we use `env_logger`
env_logger::Builder::default()
.format(move |buf, record|
// patch the env-logger entry through our drain to the tui-logger
Ok(drain.log(record))
).init(); // make this the global logger
// code....
}
For experts only ! Configure along the lines:
use tui_logger::LogFormatter;
let formatter = MyLogFormatter();
TuiLoggerWidget::default()
.block(Block::bordered().title("Filtered TuiLoggerWidget"))
.formatter(formatter)
.state(&filter_state)
.render(left, buf);
The example demo can be invoked to use a custom formatter as example for the bottom right widget.
For logging there are two circular buffers in use:
The size of the "hot" buffer is 1000 and can be modified by set_hot_buffer_depth().
The size of the main buffer is 10000 and can be modified by set_buffer_depth().
Reason for this scheme: The main buffer is locked for a while during widget updates. In order to avoid blocking the log-macros, this scheme is in use.
The copy from "hot" buffer to main buffer is performed by a call to move_events(),
which is done in a cyclic task, which repeats every 10 ms, or when the hot buffer is half full.
In versions <0.13 log messages may have been lost, if the widget wasn't drawn.
flowchart LR
Logging["Logging Macros"] --> Capture["CAPTURE Filter"] --> HotBuffer["Hot Buffer (1000 entries)"]
MoveEvents["move_events()"]
HotBuffer --> MoveEvents
MoveEvents --> MainBuffer["Main Buffer (10000 entries)"]
MainBuffer --- Show1["SHOW Filter"] --- Widget1["Widget 1"]
MainBuffer --- Show2["SHOW Filter"] --- Widget2["Widget 2"]
MainBuffer --- ShowN["SHOW Filter"] --- Widget3["Widget N"]
Config1["set_hot_buffer_depth()"] -.-> HotBuffer
Config2["set_buffer_depth()"] -.-> MainBuffer
subgraph Triggers["Triggers"]
direction TB
T1["Every 10ms"]
T2["Hot buffer 50% full"]
end
Triggers -.-> MoveEvents
note["Note: Main buffer locks during widget updates"]
note -.-> MainBuffer
License: MIT