diff --git a/Cargo.lock b/Cargo.lock index 9c6e5ba00c..c8b69e0a7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "ahash" version = "0.4.7" @@ -187,12 +185,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cassowary" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" - [[package]] name = "cc" version = "1.0.69" @@ -1054,12 +1046,6 @@ dependencies = [ "libc", ] -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" - [[package]] name = "once_cell" version = "1.8.0" @@ -1148,12 +1134,10 @@ dependencies = [ "slog-stdlog", "slog-term", "tar", - "termion", "thiserror", "tokio", "tokio-stream", "toml", - "tui", "walkdir", "workspace_hack", "zenith_utils", @@ -1246,24 +1230,6 @@ dependencies = [ "tokio-postgres 0.7.1", ] -[[package]] -name = "postgres-protocol" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff3e0f70d32e20923cabf2df02913be7c1842d4c772db8065c00fcfdd1d1bff3" -dependencies = [ - "base64", - "byteorder", - "bytes", - "fallible-iterator", - "hmac", - "md-5", - "memchr", - "rand", - "sha2", - "stringprep", -] - [[package]] name = "postgres-protocol" version = "0.6.1" @@ -1283,14 +1249,21 @@ dependencies = [ ] [[package]] -name = "postgres-types" -version = "0.2.1" +name = "postgres-protocol" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "430f4131e1b7657b0cd9a2b0c3408d77c9a43a042d300b8c77f981dffcc43a2f" +checksum = "ff3e0f70d32e20923cabf2df02913be7c1842d4c772db8065c00fcfdd1d1bff3" dependencies = [ + "base64", + "byteorder", "bytes", "fallible-iterator", - "postgres-protocol 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac", + "md-5", + "memchr", + "rand", + "sha2", + "stringprep", ] [[package]] @@ -1303,6 +1276,17 @@ dependencies = [ "postgres-protocol 0.6.1 (git+https://github.com/zenithdb/rust-postgres.git?rev=9eb0dbfbeb6a6c1b79099b9f7ae4a8c021877858)", ] +[[package]] +name = "postgres-types" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "430f4131e1b7657b0cd9a2b0c3408d77c9a43a042d300b8c77f981dffcc43a2f" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "postgres_ffi" version = "0.1.0" @@ -1434,15 +1418,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_termios" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" -dependencies = [ - "redox_syscall", -] - [[package]] name = "redox_users" version = "0.4.0" @@ -1904,18 +1879,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "termion" -version = "1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" -dependencies = [ - "libc", - "numtoa", - "redox_syscall", - "redox_termios", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -2132,19 +2095,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "tui" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ced152a8e9295a5b168adc254074525c17ac4a83c90b2716274cc38118bddc9" -dependencies = [ - "bitflags", - "cassowary", - "termion", - "unicode-segmentation", - "unicode-width", -] - [[package]] name = "typenum" version = "1.13.0" @@ -2169,12 +2119,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" - [[package]] name = "unicode-width" version = "0.1.8" diff --git a/pageserver/Cargo.toml b/pageserver/Cargo.toml index 529f55912a..f83723cac9 100644 --- a/pageserver/Cargo.toml +++ b/pageserver/Cargo.toml @@ -21,8 +21,6 @@ slog-term = "2.8.0" slog = "2.7.0" log = "0.4.14" clap = "2.33.0" -termion = "1.5.6" -tui = "0.14.0" daemonize = "0.4.1" rust-s3 = { version = "0.27.0-rc4", features = ["no-verify-ssl"] } tokio = { version = "1.3.0", features = ["full"] } diff --git a/pageserver/src/bin/pageserver.rs b/pageserver/src/bin/pageserver.rs index 31f96e366e..d31f7dc90d 100644 --- a/pageserver/src/bin/pageserver.rs +++ b/pageserver/src/bin/pageserver.rs @@ -17,7 +17,7 @@ use anyhow::Result; use clap::{App, Arg, ArgMatches}; use daemonize::Daemonize; -use pageserver::{branches, logger, page_cache, page_service, tui, PageServerConf}; +use pageserver::{branches, logger, page_cache, page_service, PageServerConf}; const DEFAULT_LISTEN_ADDR: &str = "127.0.0.1:64000"; @@ -88,7 +88,6 @@ impl CfgFileParams { Ok(PageServerConf { daemonize: false, - interactive: false, listen_addr, gc_horizon, @@ -113,13 +112,6 @@ fn main() -> Result<()> { .takes_value(true) .help("listen for incoming page requests on ip:port (default: 127.0.0.1:5430)"), ) - .arg( - Arg::with_name("interactive") - .short("i") - .long("interactive") - .takes_value(false) - .help("Interactive mode"), - ) .arg( Arg::with_name("daemonize") .short("d") @@ -189,15 +181,9 @@ fn main() -> Result<()> { let mut conf = params.try_into_config()?; conf.daemonize = arg_matches.is_present("daemonize"); - conf.interactive = arg_matches.is_present("interactive"); - if init && (conf.daemonize || conf.interactive) { - eprintln!("--daemonize and --interactive may not be used with --init"); - exit(1); - } - - if conf.daemonize && conf.interactive { - eprintln!("--daemonize is not allowed with --interactive: choose one"); + if init && conf.daemonize { + eprintln!("--daemonize cannot be used with --init"); exit(1); } @@ -230,20 +216,6 @@ fn start_pageserver(conf: &'static PageServerConf) -> Result<()> { // Note: this `info!(...)` macro comes from `log` crate info!("standard logging redirected to slog"); - let tui_thread = if conf.interactive { - // Initialize the UI - Some( - thread::Builder::new() - .name("UI thread".into()) - .spawn(|| { - let _ = tui::ui_main(); - }) - .unwrap(), - ) - } else { - None - }; - // TODO: Check that it looks like a valid repository before going further if conf.daemonize { @@ -280,14 +252,9 @@ fn start_pageserver(conf: &'static PageServerConf) -> Result<()> { .name("Page Service thread".into()) .spawn(move || page_service::thread_main(conf, pageserver_listener))?; - if let Some(tui_thread) = tui_thread { - // The TUI thread exits when the user asks to Quit. - tui_thread.join().unwrap(); - } else { - page_service_thread - .join() - .expect("Page service thread has panicked")? - } + page_service_thread + .join() + .expect("Page service thread has panicked")?; Ok(()) } diff --git a/pageserver/src/lib.rs b/pageserver/src/lib.rs index f9c3703d77..4db9e74a53 100644 --- a/pageserver/src/lib.rs +++ b/pageserver/src/lib.rs @@ -18,9 +18,6 @@ pub mod page_service; pub mod repository; pub mod restore_local_repo; pub mod rocksdb_storage; -pub mod tui; -pub mod tui_event; -mod tui_logger; pub mod waldecoder; pub mod walreceiver; pub mod walredo; @@ -28,7 +25,6 @@ pub mod walredo; #[derive(Debug, Clone)] pub struct PageServerConf { pub daemonize: bool, - pub interactive: bool, pub listen_addr: String, pub gc_horizon: u64, pub gc_period: Duration, diff --git a/pageserver/src/logger.rs b/pageserver/src/logger.rs index b1a98bbb7e..56006a54af 100644 --- a/pageserver/src/logger.rs +++ b/pageserver/src/logger.rs @@ -1,11 +1,11 @@ -use crate::{tui, PageServerConf}; +use crate::PageServerConf; use anyhow::{Context, Result}; use slog::{Drain, FnValue}; use std::fs::{File, OpenOptions}; pub fn init_logging( - conf: &PageServerConf, + _conf: &PageServerConf, log_filename: &str, ) -> Result<(slog_scope::GlobalLoggerGuard, File)> { // Don't open the same file for output multiple times; @@ -18,32 +18,28 @@ pub fn init_logging( let logger_file = log_file.try_clone().unwrap(); - if conf.interactive { - Ok((tui::init_logging(), logger_file)) - } else { - let decorator = slog_term::PlainSyncDecorator::new(logger_file); - let drain = slog_term::FullFormat::new(decorator).build(); - let drain = slog::Filter::new(drain, |record: &slog::Record| { - if record.level().is_at_least(slog::Level::Info) { - return true; - } - false - }); - let drain = std::sync::Mutex::new(drain).fuse(); - let logger = slog::Logger::root( - drain, - slog::o!( - "location" => + let decorator = slog_term::PlainSyncDecorator::new(logger_file); + let drain = slog_term::FullFormat::new(decorator).build(); + let drain = slog::Filter::new(drain, |record: &slog::Record| { + if record.level().is_at_least(slog::Level::Info) { + return true; + } + false + }); + let drain = std::sync::Mutex::new(drain).fuse(); + let logger = slog::Logger::root( + drain, + slog::o!( + "location" => FnValue(move |record| { format!("{}, {}:{}", record.module(), record.file(), record.line() - ) - } + ) + } ) - ), - ); - Ok((slog_scope::set_global_logger(logger), log_file)) - } + ), + ); + Ok((slog_scope::set_global_logger(logger), log_file)) } diff --git a/pageserver/src/repository.rs b/pageserver/src/repository.rs index ffa7cf4fe6..2b809ef563 100644 --- a/pageserver/src/repository.rs +++ b/pageserver/src/repository.rs @@ -361,7 +361,6 @@ mod tests { let conf = PageServerConf { daemonize: false, - interactive: false, gc_horizon: 64 * 1024 * 1024, gc_period: Duration::from_secs(10), listen_addr: "127.0.0.1:5430".to_string(), diff --git a/pageserver/src/tui.rs b/pageserver/src/tui.rs deleted file mode 100644 index a94719a1ab..0000000000 --- a/pageserver/src/tui.rs +++ /dev/null @@ -1,307 +0,0 @@ -use crate::tui_event::{Event, Events}; -use crate::tui_logger::TuiLogger; -use crate::tui_logger::TuiLoggerWidget; - -use lazy_static::lazy_static; -use std::sync::Arc; -use std::{error::Error, io}; -use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::AlternateScreen}; -use tui::backend::TermionBackend; -use tui::buffer::Buffer; -use tui::layout::{Constraint, Direction, Layout, Rect}; -use tui::style::{Color, Modifier, Style}; -use tui::text::{Span, Spans, Text}; -use tui::widgets::{Block, BorderType, Borders, Paragraph, Widget}; -use tui::Terminal; - -use slog::Drain; - -lazy_static! { - pub static ref PAGESERVICE_DRAIN: Arc = Arc::new(TuiLogger::default()); - pub static ref WALRECEIVER_DRAIN: Arc = Arc::new(TuiLogger::default()); - pub static ref WALREDO_DRAIN: Arc = Arc::new(TuiLogger::default()); - pub static ref CATCHALL_DRAIN: Arc = Arc::new(TuiLogger::default()); -} - -pub fn init_logging() -> slog_scope::GlobalLoggerGuard { - let pageservice_drain = - slog::Filter::new(PAGESERVICE_DRAIN.as_ref(), |record: &slog::Record| { - if record.level().is_at_least(slog::Level::Debug) - && record.module().starts_with("pageserver::page_service") - { - return true; - } - false - }) - .fuse(); - - let walredo_drain = slog::Filter::new(WALREDO_DRAIN.as_ref(), |record: &slog::Record| { - if record.level().is_at_least(slog::Level::Debug) - && record.module().starts_with("pageserver::walredo") - { - return true; - } - false - }) - .fuse(); - - let walreceiver_drain = - slog::Filter::new(WALRECEIVER_DRAIN.as_ref(), |record: &slog::Record| { - if record.level().is_at_least(slog::Level::Debug) - && record.module().starts_with("pageserver::walreceiver") - { - return true; - } - false - }) - .fuse(); - - let catchall_drain = slog::Filter::new(CATCHALL_DRAIN.as_ref(), |record: &slog::Record| { - if record.level().is_at_least(slog::Level::Info) { - return true; - } - if record.level().is_at_least(slog::Level::Debug) - && record.module().starts_with("pageserver") - { - return true; - } - false - }) - .fuse(); - - let drain = pageservice_drain; - let drain = slog::Duplicate::new(drain, walreceiver_drain).fuse(); - let drain = slog::Duplicate::new(drain, walredo_drain).fuse(); - let drain = slog::Duplicate::new(drain, catchall_drain).fuse(); - let drain = slog_async::Async::new(drain).chan_size(1000).build().fuse(); - let drain = slog::Filter::new(drain, |record: &slog::Record| { - if record.level().is_at_least(slog::Level::Info) { - return true; - } - if record.level().is_at_least(slog::Level::Debug) - && record.module().starts_with("pageserver") - { - return true; - } - - false - }) - .fuse(); - let logger = slog::Logger::root(drain, slog::o!()); - slog_scope::set_global_logger(logger) -} - -pub fn ui_main() -> Result<(), Box> { - // Terminal initialization - let stdout = io::stdout().into_raw_mode()?; - let stdout = MouseTerminal::from(stdout); - let stdout = AlternateScreen::from(stdout); - let backend = TermionBackend::new(stdout); - let mut terminal = Terminal::new(backend)?; - - // Setup event handlers - let events = Events::new(); - - loop { - terminal.draw(|f| { - let size = f.size(); - - // +----------------+----------------+ - // | | | - // | top_top_left | top_top_right | - // | | | - // +----------------+----------------| - // | | | - // | top_bot_left | top_left_right | - // | | | - // +----------------+----------------+ - // | | - // | bottom | - // | | - // +---------------------------------+ - let chunks = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Percentage(70), Constraint::Percentage(30)].as_ref()) - .split(size); - let top_chunk = chunks[0]; - let bottom_chunk = chunks[1]; - - let top_chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) - .split(top_chunk); - let top_left_chunk = top_chunks[0]; - let top_right_chunk = top_chunks[1]; - - let c = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) - .split(top_left_chunk); - let top_top_left_chunk = c[0]; - let top_bot_left_chunk = c[1]; - - let c = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) - .split(top_right_chunk); - let top_top_right_chunk = c[0]; - let top_bot_right_chunk = c[1]; - - f.render_widget( - LogWidget::new(PAGESERVICE_DRAIN.as_ref(), "Page Service"), - top_top_left_chunk, - ); - - f.render_widget( - LogWidget::new(WALREDO_DRAIN.as_ref(), "WAL Redo"), - top_bot_left_chunk, - ); - - f.render_widget( - LogWidget::new(WALRECEIVER_DRAIN.as_ref(), "WAL Receiver"), - top_top_right_chunk, - ); - - f.render_widget(MetricsWidget {}, top_bot_right_chunk); - - f.render_widget( - LogWidget::new(CATCHALL_DRAIN.as_ref(), "All Log").show_module(true), - bottom_chunk, - ); - })?; - - // If ther user presses 'q', quit. - - // silence clippy's suggestion to rewrite this as an if-statement. Match - // makes more sense as soon as we get another command than 'q'. - #[allow(clippy::single_match)] - #[allow(clippy::collapsible_match)] - if let Event::Input(key) = events.next()? { - match key { - Key::Char('q') => { - break; - } - _ => (), - } - } - } - - terminal.show_cursor().unwrap(); - terminal.clear().unwrap(); - - Ok(()) -} - -#[allow(dead_code)] -struct LogWidget<'a> { - logger: &'a TuiLogger, - title: &'a str, - show_module: bool, -} - -impl<'a> LogWidget<'a> { - fn new(logger: &'a TuiLogger, title: &'a str) -> LogWidget<'a> { - LogWidget { - logger, - title, - show_module: false, - } - } - - fn show_module(mut self, b: bool) -> LogWidget<'a> { - self.show_module = b; - self - } -} - -impl<'a> Widget for LogWidget<'a> { - fn render(self, area: Rect, buf: &mut Buffer) { - let w = TuiLoggerWidget::default(self.logger) - .block( - Block::default() - .borders(Borders::ALL) - .title(self.title) - .border_type(BorderType::Rounded), - ) - .show_module(true) - .style_error(Style::default().fg(Color::Red)) - .style_warn(Style::default().fg(Color::Yellow)) - .style_info(Style::default().fg(Color::Green)); - w.render(area, buf); - } -} - -// Render a widget to show some metrics -struct MetricsWidget {} - -fn _get_metric_u64(title: &str, value: u64) -> Spans { - Spans::from(vec![ - Span::styled(format!("{:<20}", title), Style::default()), - Span::raw(": "), - Span::styled( - value.to_string(), - Style::default().add_modifier(Modifier::BOLD), - ), - ]) -} - -// This is not used since LSNs were removed from page cache stats. -// Maybe it will be used in the future? -fn _get_metric_str<'a>(title: &str, value: &'a str) -> Spans<'a> { - Spans::from(vec![ - Span::styled(format!("{:<20}", title), Style::default()), - Span::raw(": "), - Span::styled(value, Style::default().add_modifier(Modifier::BOLD)), - ]) -} - -impl tui::widgets::Widget for MetricsWidget { - fn render(self, area: Rect, buf: &mut Buffer) { - let block = Block::default() - .borders(Borders::ALL) - .title("Page Cache Metrics") - .border_type(BorderType::Rounded); - let inner_area = block.inner(area); - - block.render(area, buf); - - #[allow(unused_mut)] - let mut lines: Vec = Vec::new(); - - // FIXME - //let page_cache_stats = crate::page_cache::get_stats(); - - // This is not used since LSNs were removed from page cache stats. - // Maybe it will be used in the future? - /* - let lsnrange = format!( - "{} - {}", - page_cache_stats.first_valid_lsn, page_cache_stats.last_valid_lsn - ); - let last_valid_recordlsn_str = page_cache_stats.last_record_lsn.to_string(); - lines.push(get_metric_str("Valid LSN range", &lsnrange)); - lines.push(get_metric_str("Last record LSN", &last_valid_recordlsn_str)); - */ - /* - lines.push(get_metric_u64( - "# of cache entries", - page_cache_stats.num_entries, - )); - lines.push(get_metric_u64( - "# of page images", - page_cache_stats.num_page_images, - )); - lines.push(get_metric_u64( - "# of WAL records", - page_cache_stats.num_wal_records, - )); - lines.push(get_metric_u64( - "# of GetPage@LSN calls", - page_cache_stats.num_getpage_requests, - )); - */ - let text = Text::from(lines); - - Paragraph::new(text).render(inner_area, buf); - } -} diff --git a/pageserver/src/tui_event.rs b/pageserver/src/tui_event.rs deleted file mode 100644 index bafb6242e5..0000000000 --- a/pageserver/src/tui_event.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::io; -use std::sync::mpsc; -use std::sync::{ - atomic::{AtomicBool, Ordering}, - Arc, -}; -use std::thread; -use std::time::Duration; - -use termion::event::Key; -use termion::input::TermRead; - -pub enum Event { - Input(I), - Tick, -} - -/// A small event handler that wrap termion input and tick events. Each event -/// type is handled in its own thread and returned to a common `Receiver` -#[allow(dead_code)] -pub struct Events { - rx: mpsc::Receiver>, - input_handle: thread::JoinHandle<()>, - ignore_exit_key: Arc, - tick_handle: thread::JoinHandle<()>, -} - -#[derive(Debug, Clone, Copy)] -pub struct Config { - pub exit_key: Key, - pub tick_rate: Duration, -} - -impl Default for Config { - fn default() -> Config { - Config { - exit_key: Key::Char('q'), - tick_rate: Duration::from_millis(250), - } - } -} - -impl Events { - pub fn new() -> Events { - Events::with_config(Config::default()) - } - - pub fn with_config(config: Config) -> Events { - let (tx, rx) = mpsc::channel(); - let ignore_exit_key = Arc::new(AtomicBool::new(false)); - let input_handle = { - let tx = tx.clone(); - let ignore_exit_key = ignore_exit_key.clone(); - thread::spawn(move || { - let stdin = io::stdin(); - for evt in stdin.keys() { - // This will panic if stdin returns EOF. - let key = evt.unwrap(); - if let Err(err) = tx.send(Event::Input(key)) { - eprintln!("{}", err); - return; - } - if !ignore_exit_key.load(Ordering::Relaxed) && key == config.exit_key { - return; - } - } - }) - }; - let tick_handle = { - thread::spawn(move || loop { - if tx.send(Event::Tick).is_err() { - break; - } - thread::sleep(config.tick_rate); - }) - }; - Events { - rx, - input_handle, - ignore_exit_key, - tick_handle, - } - } - - pub fn next(&self) -> Result, mpsc::RecvError> { - self.rx.recv() - } - - pub fn disable_exit_key(&mut self) { - self.ignore_exit_key.store(true, Ordering::Relaxed); - } - - pub fn enable_exit_key(&mut self) { - self.ignore_exit_key.store(false, Ordering::Relaxed); - } -} diff --git a/pageserver/src/tui_logger.rs b/pageserver/src/tui_logger.rs deleted file mode 100644 index 663add4065..0000000000 --- a/pageserver/src/tui_logger.rs +++ /dev/null @@ -1,199 +0,0 @@ -// -// A TUI Widget that displays log entries -// -// This is heavily inspired by gin66's tui_logger crate at https://github.com/gin66/tui-logger, -// but I wrote this based on the 'slog' module, which simplified things a lot. tui-logger also -// implemented the slog Drain trait, but it had a model of one global buffer for the records. -// With this implementation, each TuiLogger is a separate ring buffer and separate slog Drain. -// Also, I didn't do any of the "hot log" stuff that gin66's implementation had, you can use an -// AsyncDrain to buffer and handle overflow if desired. -// -use chrono::offset::Local; -use chrono::DateTime; -use slog::{Drain, Level, OwnedKVList, Record}; -use slog_async::AsyncRecord; -use std::collections::VecDeque; -use std::sync::Mutex; -use std::time::SystemTime; -use tui::buffer::Buffer; -use tui::layout::Rect; -use tui::style::{Modifier, Style}; -use tui::text::{Span, Spans}; -use tui::widgets::{Block, Paragraph, Widget, Wrap}; - -// Size of the log ring buffer, in # of records -static BUFFER_SIZE: usize = 1000; - -pub struct TuiLogger { - events: Mutex>, -} - -impl<'a> Default for TuiLogger { - fn default() -> TuiLogger { - TuiLogger { - events: Mutex::new(VecDeque::with_capacity(BUFFER_SIZE)), - } - } -} - -impl Drain for TuiLogger { - type Ok = (); - type Err = slog::Error; - - fn log(&self, record: &Record, values: &OwnedKVList) -> Result { - let mut events = self.events.lock().unwrap(); - - let now = SystemTime::now(); - let asyncrec = AsyncRecord::from(record, values); - events.push_front((now, asyncrec)); - - if events.len() > BUFFER_SIZE { - events.pop_back(); - } - - Ok(()) - } -} - -// TuiLoggerWidget renders a TuiLogger ring buffer -pub struct TuiLoggerWidget<'b> { - block: Option>, - /// Base style of the widget - style: Style, - /// Level based style - style_error: Option