Skip to content

Commit

Permalink
Made Debug Output screen behind debug_pane feature
Browse files Browse the repository at this point in the history
  • Loading branch information
AS1100K committed Jan 16, 2025
1 parent 48262d1 commit ed376a4
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 47 deletions.
13 changes: 9 additions & 4 deletions components/monitors/cu_consolemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ categories.workspace = true
homepage.workspace = true
repository.workspace = true

[features]
default = ["debug_pane"]
# Enables 'Debug Output' Pane
debug_pane = ["dep:tracing", "dep:tracing-log", "dep:chrono", "dep:dashmap"]

[dependencies]
cu29 = { workspace = true }
compact_str = { workspace = true }
Expand All @@ -23,7 +28,7 @@ tui-nodes = "0.8"
tui-widgets = "0.4" # 0.4.0 brings ratatui 0.29
color-eyre = "0.6"
gag = "1.0.0"
tracing = "0.1"
tracing-log = "0.2"
chrono = "0.4"
dashmap = "6.1"
tracing = { version = "0.1", optional = true }
tracing-log = { version = "0.2", optional = true }
chrono = { version = "0.4", optional = true }
dashmap = { version = "6.1", optional = true }
8 changes: 6 additions & 2 deletions components/monitors/cu_consolemon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@ And in you copperconfig.ron:
```

The monitor has 3 screens:
The monitor has 4 screens:

- **SysInfo**: A quick system information screen (CPU, Memory, Distrib ...)
- **DAG**: A Directed Acyclic Graph of the tasks with their real time error status and short string info.
- **Latencies**: A list of the tasks with their real time latencies & assorted statistics (Jitter, Min, Max, Avg).
- **Debug Output** [`debug_pane`](#debug_pane-feature): A pane that displays debug logs in real-time.

## `debug_pane` feature


Enabled by default. Disable with `default-features = false`. Displays real-time logs
from [tracing](https://crates.io/crates/tracing), [log](https://crates.io/crates/log), and `stderr`. Note: This crate
sets a global tracing subscriber, which may conflict with existing subscribers.
148 changes: 107 additions & 41 deletions components/monitors/cu_consolemon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ pub mod sysinfo;

use ansi_to_tui::IntoText;
use color_eyre::config::HookBuilder;
use compact_str::{CompactString, CompactStringExt, ToCompactString};
use compact_str::{CompactString, ToCompactString};
use cu29::clock::{CuDuration, RobotClock};
use cu29::config::{CuConfig, Node};
use cu29::cutask::CuMsgMetadata;
use cu29::monitoring::{CuDurationStatistics, CuMonitor, CuTaskState, Decision};
use cu29::{CuError, CuResult};
use dashmap::DashMap;
use gag::BufferRedirect;
use ratatui::backend::CrosstermBackend;
use ratatui::buffer::Buffer;
use ratatui::crossterm::event::{DisableMouseCapture, EnableMouseCapture, Event, KeyCode};
Expand All @@ -24,27 +22,41 @@ use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Text};
use ratatui::widgets::{Block, Borders, Cell, Paragraph, Row, StatefulWidget, Table};
use ratatui::{Frame, Terminal};
use std::collections::VecDeque;
use std::fmt::{Debug, Display, Formatter};
use std::io::{stdout, Read};
use std::fmt::{Display, Formatter};
use std::io::stdout;
use std::marker::PhantomData;
use std::str::FromStr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{Receiver, SyncSender};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::{io, thread};
use tracing::field::{Field, Visit};
use tracing::span::{Attributes, Record};
use tracing::{Id, Level, Metadata, Subscriber};
use tui_nodes::{Connection, NodeGraph, NodeLayout};
use tui_widgets::scrollview::{ScrollView, ScrollViewState};

#[cfg(feature = "debug_pane")]
use {
compact_str::CompactStringExt,
dashmap::DashMap,
std::collections::VecDeque,
std::fmt::Debug,
std::io::Read,
std::str::FromStr,
std::sync::mpsc::{Receiver, SyncSender},
tracing::field::{Field, Visit},
tracing::span::{Attributes, Record},
tracing::{Id, Level, Metadata, Subscriber},
};

#[cfg(feature = "debug_pane")]
const MENU_CONTENT: &str = " [1] SysInfo [2] DAG [3] Latencies [4] Debug Output [q] Quit ";
#[cfg(not(feature = "debug_pane"))]
const MENU_CONTENT: &str = " [1] SysInfo [2] DAG [3] Latencies [q] Quit ";

#[derive(PartialEq)]
enum Screen {
Neofetch,
Dag,
Latency,
#[cfg(feature = "debug_pane")]
DebugOutput,
}

Expand Down Expand Up @@ -290,16 +302,20 @@ struct UI {
sysinfo: String,
task_stats: Arc<Mutex<TaskStats>>,
nodes_scrollable_widget_state: NodesScrollableWidgetState,
error_redirect: BufferRedirect,
#[cfg(feature = "debug_pane")]
error_redirect: gag::BufferRedirect,
#[cfg(feature = "debug_pane")]
debug_output: DebugLog,
}

#[cfg(feature = "debug_pane")]
struct DebugLog {
debug_log: VecDeque<String>,
max_rows: Arc<Mutex<u16>>,
rx: Receiver<String>,
}

#[cfg(feature = "debug_pane")]
impl DebugLog {
fn new(max_lines: u16) -> (Self, SyncSender<String>) {
let (tx, rx) = std::sync::mpsc::sync_channel(1000);
Expand Down Expand Up @@ -346,19 +362,22 @@ impl DebugLog {
}
}

#[cfg(feature = "debug_pane")]
struct LogSubscriber {
tx: SyncSender<String>,
span_registry: Arc<DashMap<MetadataKey, Id>>,
next_id: Arc<Mutex<u64>>,
}

#[cfg(feature = "debug_pane")]
#[derive(Eq, PartialEq, Hash)]
struct MetadataKey {
name: String,
target: String,
level: Level,
}

#[cfg(feature = "debug_pane")]
impl From<&Metadata<'_>> for MetadataKey {
fn from(value: &Metadata<'_>) -> Self {
let level = value.target();
Expand All @@ -370,11 +389,13 @@ impl From<&Metadata<'_>> for MetadataKey {
}
}

#[cfg(feature = "debug_pane")]
#[derive(Default)]
struct MessageVisitor {
message: Option<String>,
}

#[cfg(feature = "debug_pane")]
impl LogSubscriber {
fn new(tx: SyncSender<String>) -> Self {
Self {
Expand All @@ -398,6 +419,7 @@ impl LogSubscriber {
}
}

#[cfg(feature = "debug_pane")]
impl Subscriber for LogSubscriber {
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
metadata.level() <= &Level::DEBUG
Expand Down Expand Up @@ -446,6 +468,7 @@ impl Subscriber for LogSubscriber {
}
}

#[cfg(feature = "debug_pane")]
impl Visit for MessageVisitor {
fn record_str(&mut self, field: &Field, value: &str) {
if field.name() == "message" {
Expand All @@ -461,12 +484,13 @@ impl Visit for MessageVisitor {
}

impl UI {
#[cfg(feature = "debug_pane")]
fn new(
config: CuConfig,
task_ids: &'static [&'static str],
task_stats: Arc<Mutex<TaskStats>>,
task_statuses: Arc<Mutex<Vec<TaskStatus>>>,
error_redirect: BufferRedirect,
error_redirect: gag::BufferRedirect,
debug_output: DebugLog,
) -> UI {
init_error_hooks();
Expand All @@ -484,6 +508,26 @@ impl UI {
}
}

#[cfg(not(feature = "debug_pane"))]
fn new(
config: CuConfig,
task_ids: &'static [&'static str],
task_stats: Arc<Mutex<TaskStats>>,
task_statuses: Arc<Mutex<Vec<TaskStatus>>>,
) -> UI {
init_error_hooks();
let nodes_scrollable_widget_state =
NodesScrollableWidgetState::new(&config, task_statuses.clone());

Self {
task_ids,
active_screen: Screen::Neofetch,
sysinfo: sysinfo::pfetch_info(),
task_stats,
nodes_scrollable_widget_state,
}
}

fn draw_latency_table(&self, f: &mut Frame, area: Rect) {
let header_cells = [
"🛠 Task",
Expand Down Expand Up @@ -612,6 +656,7 @@ impl UI {
)
}

#[cfg(feature = "debug_pane")]
fn draw_debug_output(&mut self, f: &mut Frame, area: Rect) {
let mut error_buffer = String::new();
self.error_redirect
Expand Down Expand Up @@ -642,14 +687,13 @@ impl UI {
)
.split(f.area());

let menu =
Paragraph::new(" [1] SysInfo [2] DAG [3] Latencies [4] Debug Output [q] Quit")
.style(
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::ITALIC),
)
.block(Block::default().borders(Borders::BOTTOM));
let menu = Paragraph::new(MENU_CONTENT)
.style(
Style::default()
.fg(Color::Yellow)
.add_modifier(Modifier::ITALIC),
)
.block(Block::default().borders(Borders::BOTTOM));
f.render_widget(menu, layout[0]);

match self.active_screen {
Expand All @@ -669,6 +713,7 @@ impl UI {
self.draw_nodes(f, layout[1]);
}
Screen::Latency => self.draw_latency_table(f, layout[1]),
#[cfg(feature = "debug_pane")]
Screen::DebugOutput => self.draw_debug_output(f, layout[1]),
};
}
Expand All @@ -685,6 +730,7 @@ impl UI {
KeyCode::Char('1') => self.active_screen = Screen::Neofetch,
KeyCode::Char('2') => self.active_screen = Screen::Dag,
KeyCode::Char('3') => self.active_screen = Screen::Latency,
#[cfg(feature = "debug_pane")]
KeyCode::Char('4') => self.active_screen = Screen::DebugOutput,
KeyCode::Char('r') => {
if self.active_screen == Screen::Latency {
Expand Down Expand Up @@ -732,7 +778,10 @@ impl UI {
}
_ => {}
}
} else if let Event::Resize(_columns, rows) = event::read()? {
}

#[cfg(feature = "debug_pane")]
if let Event::Resize(_columns, rows) = event::read()? {
*self.debug_output.max_rows.lock().unwrap() = rows;
}
}
Expand Down Expand Up @@ -776,29 +825,46 @@ impl CuMonitor for CuConsoleMon {

let mut terminal =
Terminal::new(backend).expect("Failed to initialize terminal backend");
let max_lines = terminal.size().unwrap().height - 5;

// redirect stderr, so it doesn't pop in the terminal
let error_redirect = BufferRedirect::stderr().unwrap();
let (debug_log, tx) = DebugLog::new(max_lines);

let mut ui = UI::new(
config_dup,
taskids,
task_stats_ui,
error_states,
error_redirect,
debug_log,
);

tracing_log::LogTracer::init().expect("Failed to setup log tracer");
let log_subscriber = LogSubscriber::new(tx);
tracing::subscriber::set_global_default(log_subscriber)
.expect("Failed to set global subscriber");
#[cfg(feature = "debug_pane")]
{
let max_lines = terminal.size().unwrap().height - 5;
let (debug_log, tx) = DebugLog::new(max_lines);

// redirect stderr, so it doesn't pop in the terminal
let error_redirect = gag::BufferRedirect::stderr().unwrap();

let mut ui = UI::new(
config_dup,
taskids,
task_stats_ui,
error_states,
error_redirect,
debug_log,
);

tracing_log::LogTracer::init().expect("Failed to setup log tracer");
let log_subscriber = LogSubscriber::new(tx);
tracing::subscriber::set_global_default(log_subscriber)
.expect("Failed to set global subscriber");

ui.run_app(&mut terminal).expect("Failed to run app");
}

#[cfg(not(feature = "debug_pane"))]
let stderr_gag = gag::Gag::stderr().unwrap(); // need to declare it separately, so it doesn't drop

#[cfg(not(feature = "debug_pane"))]
{
let mut ui = UI::new(config_dup, taskids, task_stats_ui, error_states);

ui.run_app(&mut terminal).expect("Failed to run app");
}

ui.run_app(&mut terminal).expect("Failed to run app");
quitting.store(true, Ordering::SeqCst);
// restoring the terminal
#[cfg(not(feature = "debug_pane"))]
drop(stderr_gag);
restore_terminal();
});

Expand Down

0 comments on commit ed376a4

Please sign in to comment.