2024-06-19 17:29:19 -07:00
|
|
|
//! # [Ratatui] Tracing example
|
|
|
|
//!
|
|
|
|
//! The latest version of this example is available in the [examples] folder in the repository.
|
|
|
|
//!
|
|
|
|
//! Please note that the examples are designed to be run against the `main` branch of the Github
|
|
|
|
//! repository. This means that you may not be able to compile with the latest release version on
|
|
|
|
//! crates.io, or the one that you have installed locally.
|
|
|
|
//!
|
|
|
|
//! See the [examples readme] for more information on finding examples that match the version of the
|
|
|
|
//! library you are using.
|
|
|
|
//!
|
2024-08-21 11:35:08 -07:00
|
|
|
//! [Ratatui]: https://github.com/ratatui/ratatui
|
|
|
|
//! [examples]: https://github.com/ratatui/ratatui/blob/main/examples
|
|
|
|
//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
|
2024-06-19 17:29:19 -07:00
|
|
|
|
|
|
|
// A simple example demonstrating how to use the [tracing] with Ratatui to log to a file.
|
|
|
|
//
|
|
|
|
// This example demonstrates how to use the [tracing] crate with Ratatui to log to a file. The
|
|
|
|
// example sets up a simple logger that logs to a file named `tracing.log` in the current directory.
|
|
|
|
//
|
|
|
|
// Run the example with `cargo run --example tracing` and then view the `tracing.log` file to see
|
|
|
|
// the logs. To see more logs, you can run the example with `RUST_LOG=tracing=debug cargo run
|
|
|
|
// --example`
|
|
|
|
//
|
|
|
|
// For a helpful widget that handles logging, see the [tui-logger] crate.
|
|
|
|
//
|
|
|
|
// [tracing]: https://crates.io/crates/tracing
|
|
|
|
// [tui-logger]: https://crates.io/crates/tui-logger
|
|
|
|
|
feat(terminal): Add ratatui::init() and restore() methods (#1289)
These are simple opinionated methods for creating a terminal that is
useful to use in most apps. The new init method creates a crossterm
backend writing to stdout, enables raw mode, enters the alternate
screen, and sets a panic handler that restores the terminal on panic.
A minimal hello world now looks a bit like:
```rust
use ratatui::{
crossterm::event::{self, Event},
text::Text,
Frame,
};
fn main() {
let mut terminal = ratatui::init();
loop {
terminal
.draw(|frame: &mut Frame| frame.render_widget(Text::raw("Hello World!"), frame.area()))
.expect("Failed to draw");
if matches!(event::read().expect("failed to read event"), Event::Key(_)) {
break;
}
}
ratatui::restore();
}
```
A type alias `DefaultTerminal` is added to represent this terminal
type and to simplify any cases where applications need to pass this
terminal around. It is equivalent to:
`Terminal<CrosstermBackend<Stdout>>`
We also added `ratatui::try_init()` and `try_restore()`, for situations
where you might want to handle initialization errors yourself instead
of letting the panic handler fire and cleanup. Simple Apps should
prefer the `init` and `restore` functions over these functions.
Corresponding functions to allow passing a `TerminalOptions` with
a `Viewport` (e.g. inline, fixed) are also available
(`init_with_options`,
and `try_init_with_options`).
The existing code to create a backend and terminal will remain and
is not deprecated by this approach. This just provides a simple one
line initialization using the common options.
---------
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-08-22 05:16:35 -07:00
|
|
|
use std::{fs::File, time::Duration};
|
2024-06-19 17:29:19 -07:00
|
|
|
|
feat(terminal): Add ratatui::init() and restore() methods (#1289)
These are simple opinionated methods for creating a terminal that is
useful to use in most apps. The new init method creates a crossterm
backend writing to stdout, enables raw mode, enters the alternate
screen, and sets a panic handler that restores the terminal on panic.
A minimal hello world now looks a bit like:
```rust
use ratatui::{
crossterm::event::{self, Event},
text::Text,
Frame,
};
fn main() {
let mut terminal = ratatui::init();
loop {
terminal
.draw(|frame: &mut Frame| frame.render_widget(Text::raw("Hello World!"), frame.area()))
.expect("Failed to draw");
if matches!(event::read().expect("failed to read event"), Event::Key(_)) {
break;
}
}
ratatui::restore();
}
```
A type alias `DefaultTerminal` is added to represent this terminal
type and to simplify any cases where applications need to pass this
terminal around. It is equivalent to:
`Terminal<CrosstermBackend<Stdout>>`
We also added `ratatui::try_init()` and `try_restore()`, for situations
where you might want to handle initialization errors yourself instead
of letting the panic handler fire and cleanup. Simple Apps should
prefer the `init` and `restore` functions over these functions.
Corresponding functions to allow passing a `TerminalOptions` with
a `Viewport` (e.g. inline, fixed) are also available
(`init_with_options`,
and `try_init_with_options`).
The existing code to create a backend and terminal will remain and
is not deprecated by this approach. This just provides a simple one
line initialization using the common options.
---------
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-08-22 05:16:35 -07:00
|
|
|
use color_eyre::{eyre::Context, Result};
|
2024-06-19 17:29:19 -07:00
|
|
|
use ratatui::{
|
feat(terminal): Add ratatui::init() and restore() methods (#1289)
These are simple opinionated methods for creating a terminal that is
useful to use in most apps. The new init method creates a crossterm
backend writing to stdout, enables raw mode, enters the alternate
screen, and sets a panic handler that restores the terminal on panic.
A minimal hello world now looks a bit like:
```rust
use ratatui::{
crossterm::event::{self, Event},
text::Text,
Frame,
};
fn main() {
let mut terminal = ratatui::init();
loop {
terminal
.draw(|frame: &mut Frame| frame.render_widget(Text::raw("Hello World!"), frame.area()))
.expect("Failed to draw");
if matches!(event::read().expect("failed to read event"), Event::Key(_)) {
break;
}
}
ratatui::restore();
}
```
A type alias `DefaultTerminal` is added to represent this terminal
type and to simplify any cases where applications need to pass this
terminal around. It is equivalent to:
`Terminal<CrosstermBackend<Stdout>>`
We also added `ratatui::try_init()` and `try_restore()`, for situations
where you might want to handle initialization errors yourself instead
of letting the panic handler fire and cleanup. Simple Apps should
prefer the `init` and `restore` functions over these functions.
Corresponding functions to allow passing a `TerminalOptions` with
a `Viewport` (e.g. inline, fixed) are also available
(`init_with_options`,
and `try_init_with_options`).
The existing code to create a backend and terminal will remain and
is not deprecated by this approach. This just provides a simple one
line initialization using the common options.
---------
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-08-22 05:16:35 -07:00
|
|
|
crossterm::event::{self, Event, KeyCode},
|
2024-06-19 17:29:19 -07:00
|
|
|
widgets::{Block, Paragraph},
|
feat(terminal): Add ratatui::init() and restore() methods (#1289)
These are simple opinionated methods for creating a terminal that is
useful to use in most apps. The new init method creates a crossterm
backend writing to stdout, enables raw mode, enters the alternate
screen, and sets a panic handler that restores the terminal on panic.
A minimal hello world now looks a bit like:
```rust
use ratatui::{
crossterm::event::{self, Event},
text::Text,
Frame,
};
fn main() {
let mut terminal = ratatui::init();
loop {
terminal
.draw(|frame: &mut Frame| frame.render_widget(Text::raw("Hello World!"), frame.area()))
.expect("Failed to draw");
if matches!(event::read().expect("failed to read event"), Event::Key(_)) {
break;
}
}
ratatui::restore();
}
```
A type alias `DefaultTerminal` is added to represent this terminal
type and to simplify any cases where applications need to pass this
terminal around. It is equivalent to:
`Terminal<CrosstermBackend<Stdout>>`
We also added `ratatui::try_init()` and `try_restore()`, for situations
where you might want to handle initialization errors yourself instead
of letting the panic handler fire and cleanup. Simple Apps should
prefer the `init` and `restore` functions over these functions.
Corresponding functions to allow passing a `TerminalOptions` with
a `Viewport` (e.g. inline, fixed) are also available
(`init_with_options`,
and `try_init_with_options`).
The existing code to create a backend and terminal will remain and
is not deprecated by this approach. This just provides a simple one
line initialization using the common options.
---------
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-08-22 05:16:35 -07:00
|
|
|
Frame,
|
2024-06-19 17:29:19 -07:00
|
|
|
};
|
|
|
|
use tracing::{debug, info, instrument, trace, Level};
|
|
|
|
use tracing_appender::{non_blocking, non_blocking::WorkerGuard};
|
|
|
|
use tracing_subscriber::EnvFilter;
|
|
|
|
|
|
|
|
fn main() -> Result<()> {
|
feat(terminal): Add ratatui::init() and restore() methods (#1289)
These are simple opinionated methods for creating a terminal that is
useful to use in most apps. The new init method creates a crossterm
backend writing to stdout, enables raw mode, enters the alternate
screen, and sets a panic handler that restores the terminal on panic.
A minimal hello world now looks a bit like:
```rust
use ratatui::{
crossterm::event::{self, Event},
text::Text,
Frame,
};
fn main() {
let mut terminal = ratatui::init();
loop {
terminal
.draw(|frame: &mut Frame| frame.render_widget(Text::raw("Hello World!"), frame.area()))
.expect("Failed to draw");
if matches!(event::read().expect("failed to read event"), Event::Key(_)) {
break;
}
}
ratatui::restore();
}
```
A type alias `DefaultTerminal` is added to represent this terminal
type and to simplify any cases where applications need to pass this
terminal around. It is equivalent to:
`Terminal<CrosstermBackend<Stdout>>`
We also added `ratatui::try_init()` and `try_restore()`, for situations
where you might want to handle initialization errors yourself instead
of letting the panic handler fire and cleanup. Simple Apps should
prefer the `init` and `restore` functions over these functions.
Corresponding functions to allow passing a `TerminalOptions` with
a `Viewport` (e.g. inline, fixed) are also available
(`init_with_options`,
and `try_init_with_options`).
The existing code to create a backend and terminal will remain and
is not deprecated by this approach. This just provides a simple one
line initialization using the common options.
---------
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-08-22 05:16:35 -07:00
|
|
|
color_eyre::install()?;
|
|
|
|
|
2024-06-19 17:29:19 -07:00
|
|
|
let _guard = init_tracing()?;
|
|
|
|
info!("Starting tracing example");
|
|
|
|
|
feat(terminal): Add ratatui::init() and restore() methods (#1289)
These are simple opinionated methods for creating a terminal that is
useful to use in most apps. The new init method creates a crossterm
backend writing to stdout, enables raw mode, enters the alternate
screen, and sets a panic handler that restores the terminal on panic.
A minimal hello world now looks a bit like:
```rust
use ratatui::{
crossterm::event::{self, Event},
text::Text,
Frame,
};
fn main() {
let mut terminal = ratatui::init();
loop {
terminal
.draw(|frame: &mut Frame| frame.render_widget(Text::raw("Hello World!"), frame.area()))
.expect("Failed to draw");
if matches!(event::read().expect("failed to read event"), Event::Key(_)) {
break;
}
}
ratatui::restore();
}
```
A type alias `DefaultTerminal` is added to represent this terminal
type and to simplify any cases where applications need to pass this
terminal around. It is equivalent to:
`Terminal<CrosstermBackend<Stdout>>`
We also added `ratatui::try_init()` and `try_restore()`, for situations
where you might want to handle initialization errors yourself instead
of letting the panic handler fire and cleanup. Simple Apps should
prefer the `init` and `restore` functions over these functions.
Corresponding functions to allow passing a `TerminalOptions` with
a `Viewport` (e.g. inline, fixed) are also available
(`init_with_options`,
and `try_init_with_options`).
The existing code to create a backend and terminal will remain and
is not deprecated by this approach. This just provides a simple one
line initialization using the common options.
---------
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-08-22 05:16:35 -07:00
|
|
|
let mut terminal = ratatui::init();
|
2024-06-19 17:29:19 -07:00
|
|
|
let mut events = vec![]; // a buffer to store the recent events to display in the UI
|
|
|
|
while !should_exit(&events) {
|
|
|
|
handle_events(&mut events)?;
|
feat(terminal): Add ratatui::init() and restore() methods (#1289)
These are simple opinionated methods for creating a terminal that is
useful to use in most apps. The new init method creates a crossterm
backend writing to stdout, enables raw mode, enters the alternate
screen, and sets a panic handler that restores the terminal on panic.
A minimal hello world now looks a bit like:
```rust
use ratatui::{
crossterm::event::{self, Event},
text::Text,
Frame,
};
fn main() {
let mut terminal = ratatui::init();
loop {
terminal
.draw(|frame: &mut Frame| frame.render_widget(Text::raw("Hello World!"), frame.area()))
.expect("Failed to draw");
if matches!(event::read().expect("failed to read event"), Event::Key(_)) {
break;
}
}
ratatui::restore();
}
```
A type alias `DefaultTerminal` is added to represent this terminal
type and to simplify any cases where applications need to pass this
terminal around. It is equivalent to:
`Terminal<CrosstermBackend<Stdout>>`
We also added `ratatui::try_init()` and `try_restore()`, for situations
where you might want to handle initialization errors yourself instead
of letting the panic handler fire and cleanup. Simple Apps should
prefer the `init` and `restore` functions over these functions.
Corresponding functions to allow passing a `TerminalOptions` with
a `Viewport` (e.g. inline, fixed) are also available
(`init_with_options`,
and `try_init_with_options`).
The existing code to create a backend and terminal will remain and
is not deprecated by this approach. This just provides a simple one
line initialization using the common options.
---------
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-08-22 05:16:35 -07:00
|
|
|
terminal.draw(|frame| draw(frame, &events))?;
|
2024-06-19 17:29:19 -07:00
|
|
|
}
|
feat(terminal): Add ratatui::init() and restore() methods (#1289)
These are simple opinionated methods for creating a terminal that is
useful to use in most apps. The new init method creates a crossterm
backend writing to stdout, enables raw mode, enters the alternate
screen, and sets a panic handler that restores the terminal on panic.
A minimal hello world now looks a bit like:
```rust
use ratatui::{
crossterm::event::{self, Event},
text::Text,
Frame,
};
fn main() {
let mut terminal = ratatui::init();
loop {
terminal
.draw(|frame: &mut Frame| frame.render_widget(Text::raw("Hello World!"), frame.area()))
.expect("Failed to draw");
if matches!(event::read().expect("failed to read event"), Event::Key(_)) {
break;
}
}
ratatui::restore();
}
```
A type alias `DefaultTerminal` is added to represent this terminal
type and to simplify any cases where applications need to pass this
terminal around. It is equivalent to:
`Terminal<CrosstermBackend<Stdout>>`
We also added `ratatui::try_init()` and `try_restore()`, for situations
where you might want to handle initialization errors yourself instead
of letting the panic handler fire and cleanup. Simple Apps should
prefer the `init` and `restore` functions over these functions.
Corresponding functions to allow passing a `TerminalOptions` with
a `Viewport` (e.g. inline, fixed) are also available
(`init_with_options`,
and `try_init_with_options`).
The existing code to create a backend and terminal will remain and
is not deprecated by this approach. This just provides a simple one
line initialization using the common options.
---------
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-08-22 05:16:35 -07:00
|
|
|
ratatui::restore();
|
|
|
|
|
2024-06-19 17:29:19 -07:00
|
|
|
info!("Exiting tracing example");
|
|
|
|
println!("See the tracing.log file for the logs");
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn should_exit(events: &[Event]) -> bool {
|
|
|
|
events
|
|
|
|
.iter()
|
|
|
|
.any(|event| matches!(event, Event::Key(key) if key.code == KeyCode::Char('q')))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Handle events and insert them into the events vector keeping only the last 10 events
|
|
|
|
#[instrument(skip(events))]
|
|
|
|
fn handle_events(events: &mut Vec<Event>) -> Result<()> {
|
|
|
|
// Render the UI at least once every 100ms
|
|
|
|
if event::poll(Duration::from_millis(100))? {
|
|
|
|
let event = event::read()?;
|
|
|
|
debug!(?event);
|
|
|
|
events.insert(0, event);
|
|
|
|
}
|
|
|
|
events.truncate(10);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[instrument(skip_all)]
|
feat(terminal): Add ratatui::init() and restore() methods (#1289)
These are simple opinionated methods for creating a terminal that is
useful to use in most apps. The new init method creates a crossterm
backend writing to stdout, enables raw mode, enters the alternate
screen, and sets a panic handler that restores the terminal on panic.
A minimal hello world now looks a bit like:
```rust
use ratatui::{
crossterm::event::{self, Event},
text::Text,
Frame,
};
fn main() {
let mut terminal = ratatui::init();
loop {
terminal
.draw(|frame: &mut Frame| frame.render_widget(Text::raw("Hello World!"), frame.area()))
.expect("Failed to draw");
if matches!(event::read().expect("failed to read event"), Event::Key(_)) {
break;
}
}
ratatui::restore();
}
```
A type alias `DefaultTerminal` is added to represent this terminal
type and to simplify any cases where applications need to pass this
terminal around. It is equivalent to:
`Terminal<CrosstermBackend<Stdout>>`
We also added `ratatui::try_init()` and `try_restore()`, for situations
where you might want to handle initialization errors yourself instead
of letting the panic handler fire and cleanup. Simple Apps should
prefer the `init` and `restore` functions over these functions.
Corresponding functions to allow passing a `TerminalOptions` with
a `Viewport` (e.g. inline, fixed) are also available
(`init_with_options`,
and `try_init_with_options`).
The existing code to create a backend and terminal will remain and
is not deprecated by this approach. This just provides a simple one
line initialization using the common options.
---------
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-08-22 05:16:35 -07:00
|
|
|
fn draw(frame: &mut Frame, events: &[Event]) {
|
2024-06-19 17:29:19 -07:00
|
|
|
// To view this event, run the example with `RUST_LOG=tracing=debug cargo run --example tracing`
|
|
|
|
trace!(frame_count = frame.count(), event_count = events.len());
|
|
|
|
let events = events.iter().map(|e| format!("{e:?}")).collect::<Vec<_>>();
|
|
|
|
let paragraph = Paragraph::new(events.join("\n"))
|
|
|
|
.block(Block::bordered().title("Tracing example. Press 'q' to quit."));
|
2024-08-06 05:15:14 +02:00
|
|
|
frame.render_widget(paragraph, frame.area());
|
2024-06-19 17:29:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Initialize the tracing subscriber to log to a file
|
|
|
|
///
|
|
|
|
/// This function initializes the tracing subscriber to log to a file named `tracing.log` in the
|
|
|
|
/// current directory. The function returns a [`WorkerGuard`] that must be kept alive for the
|
|
|
|
/// duration of the program to ensure that logs are flushed to the file on shutdown. The logs are
|
|
|
|
/// written in a non-blocking fashion to ensure that the logs do not block the main thread.
|
|
|
|
fn init_tracing() -> Result<WorkerGuard> {
|
|
|
|
let file = File::create("tracing.log").wrap_err("failed to create tracing.log")?;
|
|
|
|
let (non_blocking, guard) = non_blocking(file);
|
|
|
|
|
|
|
|
// By default, the subscriber is configured to log all events with a level of `DEBUG` or higher,
|
|
|
|
// but this can be changed by setting the `RUST_LOG` environment variable.
|
|
|
|
let env_filter = EnvFilter::builder()
|
|
|
|
.with_default_directive(Level::DEBUG.into())
|
|
|
|
.from_env_lossy();
|
|
|
|
|
|
|
|
tracing_subscriber::fmt()
|
|
|
|
.with_writer(non_blocking)
|
|
|
|
.with_env_filter(env_filter)
|
|
|
|
.init();
|
|
|
|
Ok(guard)
|
|
|
|
}
|