[go: up one dir, main page]

tracing/
tracing.rs

1//! # [Ratatui] Tracing example
2//!
3//! The latest version of this example is available in the [examples] folder in the repository.
4//!
5//! Please note that the examples are designed to be run against the `main` branch of the Github
6//! repository. This means that you may not be able to compile with the latest release version on
7//! crates.io, or the one that you have installed locally.
8//!
9//! See the [examples readme] for more information on finding examples that match the version of the
10//! library you are using.
11//!
12//! [Ratatui]: https://github.com/ratatui/ratatui
13//! [examples]: https://github.com/ratatui/ratatui/blob/main/examples
14//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
15
16// A simple example demonstrating how to use the [tracing] with Ratatui to log to a file.
17//
18// This example demonstrates how to use the [tracing] crate with Ratatui to log to a file. The
19// example sets up a simple logger that logs to a file named `tracing.log` in the current directory.
20//
21// Run the example with `cargo run --example tracing` and then view the `tracing.log` file to see
22// the logs. To see more logs, you can run the example with `RUST_LOG=tracing=debug cargo run
23// --example`
24//
25// For a helpful widget that handles logging, see the [tui-logger] crate.
26//
27// [tracing]: https://crates.io/crates/tracing
28// [tui-logger]: https://crates.io/crates/tui-logger
29
30use std::{fs::File, time::Duration};
31
32use color_eyre::{eyre::Context, Result};
33use ratatui::{
34    crossterm::event::{self, Event, KeyCode},
35    widgets::{Block, Paragraph},
36    Frame,
37};
38use tracing::{debug, info, instrument, trace, Level};
39use tracing_appender::{non_blocking, non_blocking::WorkerGuard};
40use tracing_subscriber::EnvFilter;
41
42fn main() -> Result<()> {
43    color_eyre::install()?;
44
45    let _guard = init_tracing()?;
46    info!("Starting tracing example");
47
48    let mut terminal = ratatui::init();
49    let mut events = vec![]; // a buffer to store the recent events to display in the UI
50    while !should_exit(&events) {
51        handle_events(&mut events)?;
52        terminal.draw(|frame| draw(frame, &events))?;
53    }
54    ratatui::restore();
55
56    info!("Exiting tracing example");
57    println!("See the tracing.log file for the logs");
58    Ok(())
59}
60
61fn should_exit(events: &[Event]) -> bool {
62    events
63        .iter()
64        .any(|event| matches!(event, Event::Key(key) if key.code == KeyCode::Char('q')))
65}
66
67/// Handle events and insert them into the events vector keeping only the last 10 events
68#[instrument(skip(events))]
69fn handle_events(events: &mut Vec<Event>) -> Result<()> {
70    // Render the UI at least once every 100ms
71    if event::poll(Duration::from_millis(100))? {
72        let event = event::read()?;
73        debug!(?event);
74        events.insert(0, event);
75    }
76    events.truncate(10);
77    Ok(())
78}
79
80#[instrument(skip_all)]
81fn draw(frame: &mut Frame, events: &[Event]) {
82    // To view this event, run the example with `RUST_LOG=tracing=debug cargo run --example tracing`
83    trace!(frame_count = frame.count(), event_count = events.len());
84    let events = events.iter().map(|e| format!("{e:?}")).collect::<Vec<_>>();
85    let paragraph = Paragraph::new(events.join("\n"))
86        .block(Block::bordered().title("Tracing example. Press 'q' to quit."));
87    frame.render_widget(paragraph, frame.area());
88}
89
90/// Initialize the tracing subscriber to log to a file
91///
92/// This function initializes the tracing subscriber to log to a file named `tracing.log` in the
93/// current directory. The function returns a [`WorkerGuard`] that must be kept alive for the
94/// duration of the program to ensure that logs are flushed to the file on shutdown. The logs are
95/// written in a non-blocking fashion to ensure that the logs do not block the main thread.
96fn init_tracing() -> Result<WorkerGuard> {
97    let file = File::create("tracing.log").wrap_err("failed to create tracing.log")?;
98    let (non_blocking, guard) = non_blocking(file);
99
100    // By default, the subscriber is configured to log all events with a level of `DEBUG` or higher,
101    // but this can be changed by setting the `RUST_LOG` environment variable.
102    let env_filter = EnvFilter::builder()
103        .with_default_directive(Level::DEBUG.into())
104        .from_env_lossy();
105
106    tracing_subscriber::fmt()
107        .with_writer(non_blocking)
108        .with_env_filter(env_filter)
109        .init();
110    Ok(guard)
111}