diff --git a/config/src/comments.rs b/config/src/comments.rs index 0bb5680e5..12b3b6bc3 100644 --- a/config/src/comments.rs +++ b/config/src/comments.rs @@ -114,8 +114,7 @@ fn comments() -> HashMap { retval.insert( "run_tui".to_string(), " -#whether to run the ncurses TUI. Ncurses must be installed and this -#will also disable logging to stdout +#whether to run the ncurses TUI (Ncurses must be installed) " .to_string(), ); diff --git a/config/src/config.rs b/config/src/config.rs index 6e5a54669..71f7491b6 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -30,7 +30,7 @@ use crate::core::global; use crate::p2p; use crate::servers::ServerConfig; use crate::types::{ConfigError, ConfigMembers, GlobalConfig}; -use crate::util::LoggingConfig; +use crate::util::logger::LoggingConfig; /// The default file name to use when trying to derive /// the node config file location diff --git a/config/src/types.rs b/config/src/types.rs index 12c745797..7572b4a23 100644 --- a/config/src/types.rs +++ b/config/src/types.rs @@ -19,7 +19,7 @@ use std::io; use std::path::PathBuf; use crate::servers::ServerConfig; -use crate::util::LoggingConfig; +use crate::util::logger::LoggingConfig; /// Error type wrapping config errors. #[derive(Debug)] diff --git a/servers/src/common.rs b/servers/src/common.rs index 98dc99108..27cc71003 100644 --- a/servers/src/common.rs +++ b/servers/src/common.rs @@ -15,6 +15,6 @@ //! Modules common to all Grin server types pub mod adapters; +pub mod hooks; pub mod stats; pub mod types; -pub mod hooks; diff --git a/servers/src/grin/server.rs b/servers/src/grin/server.rs index 3d13a07c6..0b3f67cb7 100644 --- a/servers/src/grin/server.rs +++ b/servers/src/grin/server.rs @@ -20,7 +20,7 @@ use std::fs; use std::fs::File; use std::io::prelude::*; use std::path::Path; -use std::sync::Arc; +use std::sync::{mpsc, Arc}; use std::{ thread::{self, JoinHandle}, time, @@ -52,6 +52,7 @@ use crate::p2p::types::PeerAddr; use crate::pool; use crate::util::file::get_first_line; use crate::util::{RwLock, StopState}; +use grin_util::logger::LogEntry; /// Grin server holding internal structures. pub struct Server { @@ -83,9 +84,13 @@ impl Server { /// Instantiates and starts a new server. Optionally takes a callback /// for the server to send an ARC copy of itself, to allow another process /// to poll info about the server status - pub fn start(config: ServerConfig, mut info_callback: F) -> Result<(), Error> + pub fn start( + config: ServerConfig, + logs_rx: Option>, + mut info_callback: F, + ) -> Result<(), Error> where - F: FnMut(Server), + F: FnMut(Server, Option>), { let mining_config = config.stratum_mining_config.clone(); let enable_test_miner = config.run_test_miner; @@ -111,7 +116,7 @@ impl Server { } } - info_callback(serv); + info_callback(serv, logs_rx); Ok(()) } @@ -555,9 +560,10 @@ impl Server { } } // this call is blocking and makes sure all peers stop, however - // we can't be sure that we stoped a listener blocked on accept, so we don't join the p2p thread + // we can't be sure that we stopped a listener blocked on accept, so we don't join the p2p thread self.p2p.stop(); let _ = self.lock_file.unlock(); + warn!("Shutdown complete"); } /// Pause the p2p server. diff --git a/src/bin/cmd/server.rs b/src/bin/cmd/server.rs index 72c7d127f..25ab7994e 100644 --- a/src/bin/cmd/server.rs +++ b/src/bin/cmd/server.rs @@ -27,46 +27,53 @@ use crate::core::global; use crate::p2p::{PeerAddr, Seeding}; use crate::servers; use crate::tui::ui; +use grin_util::logger::LogEntry; +use std::sync::mpsc; /// wrap below to allow UI to clean up on stop -pub fn start_server(config: servers::ServerConfig) { - start_server_tui(config); +pub fn start_server(config: servers::ServerConfig, logs_rx: Option>) { + start_server_tui(config, logs_rx); // Just kill process for now, otherwise the process // hangs around until sigint because the API server // currently has no shutdown facility - warn!("Shutting down..."); - thread::sleep(Duration::from_millis(1000)); - warn!("Shutdown complete."); exit(0); } -fn start_server_tui(config: servers::ServerConfig) { +fn start_server_tui(config: servers::ServerConfig, logs_rx: Option>) { // Run the UI controller.. here for now for simplicity to access // everything it might need if config.run_tui.unwrap_or(false) { warn!("Starting GRIN in UI mode..."); - servers::Server::start(config, |serv: servers::Server| { - let mut controller = ui::Controller::new().unwrap_or_else(|e| { - panic!("Error loading UI controller: {}", e); - }); - controller.run(serv); - }) + servers::Server::start( + config, + logs_rx, + |serv: servers::Server, logs_rx: Option>| { + let mut controller = ui::Controller::new(logs_rx.unwrap()).unwrap_or_else(|e| { + panic!("Error loading UI controller: {}", e); + }); + controller.run(serv); + }, + ) .unwrap(); } else { warn!("Starting GRIN w/o UI..."); - servers::Server::start(config, |serv: servers::Server| { - let running = Arc::new(AtomicBool::new(true)); - let r = running.clone(); - ctrlc::set_handler(move || { - r.store(false, Ordering::SeqCst); - }) - .expect("Error setting handler for both SIGINT (Ctrl+C) and SIGTERM (kill)"); - while running.load(Ordering::SeqCst) { - thread::sleep(Duration::from_secs(1)); - } - warn!("Received SIGINT (Ctrl+C) or SIGTERM (kill)."); - serv.stop(); - }) + servers::Server::start( + config, + logs_rx, + |serv: servers::Server, _: Option>| { + let running = Arc::new(AtomicBool::new(true)); + let r = running.clone(); + ctrlc::set_handler(move || { + r.store(false, Ordering::SeqCst); + }) + .expect("Error setting handler for both SIGINT (Ctrl+C) and SIGTERM (kill)"); + while running.load(Ordering::SeqCst) { + thread::sleep(Duration::from_secs(1)); + } + warn!("Received SIGINT (Ctrl+C) or SIGTERM (kill)."); + serv.stop(); + }, + ) .unwrap(); } } @@ -78,6 +85,7 @@ fn start_server_tui(config: servers::ServerConfig) { pub fn server_command( server_args: Option<&ArgMatches<'_>>, mut global_config: GlobalConfig, + logs_rx: Option>, ) -> i32 { global::set_mining_mode( global_config @@ -123,7 +131,7 @@ pub fn server_command( if let Some(a) = server_args { match a.subcommand() { ("run", _) => { - start_server(server_config); + start_server(server_config, logs_rx); } ("", _) => { println!("Subcommand required, use 'grin help server' for details"); @@ -137,7 +145,7 @@ pub fn server_command( } } } else { - start_server(server_config); + start_server(server_config, logs_rx); } 0 } diff --git a/src/bin/grin.rs b/src/bin/grin.rs index 281b4e2e2..886c586f7 100644 --- a/src/bin/grin.rs +++ b/src/bin/grin.rs @@ -30,6 +30,8 @@ use grin_core as core; use grin_p2p as p2p; use grin_servers as servers; use grin_util as util; +use grin_util::logger::LogEntry; +use std::sync::mpsc; mod cmd; pub mod tui; @@ -136,26 +138,28 @@ fn real_main() -> i32 { } } - if let Some(mut config) = node_config.clone() { - let mut l = config.members.as_mut().unwrap().logging.clone().unwrap(); - let run_tui = config.members.as_mut().unwrap().server.run_tui; - if let Some(true) = run_tui { - l.log_to_stdout = false; - l.tui_running = Some(true); - } - init_logger(Some(l)); + let mut config = node_config.clone().unwrap(); + let mut logging_config = config.members.as_mut().unwrap().logging.clone().unwrap(); + logging_config.tui_running = config.members.as_mut().unwrap().server.run_tui; - global::set_mining_mode(config.members.unwrap().server.clone().chain_type); + let (logs_tx, logs_rx) = if logging_config.tui_running.unwrap() { + let (logs_tx, logs_rx) = mpsc::sync_channel::(200); + (Some(logs_tx), Some(logs_rx)) + } else { + (None, None) + }; + init_logger(Some(logging_config), logs_tx); - if let Some(file_path) = &config.config_file_path { - info!( - "Using configuration file at {}", - file_path.to_str().unwrap() - ); - } else { - info!("Node configuration file not found, using default"); - } - } + global::set_mining_mode(config.members.unwrap().server.clone().chain_type); + + if let Some(file_path) = &config.config_file_path { + info!( + "Using configuration file at {}", + file_path.to_str().unwrap() + ); + } else { + info!("Node configuration file not found, using default"); + }; log_build_info(); @@ -163,7 +167,7 @@ fn real_main() -> i32 { match args.subcommand() { // server commands and options ("server", Some(server_args)) => { - cmd::server_command(Some(server_args), node_config.unwrap()) + cmd::server_command(Some(server_args), node_config.unwrap(), logs_rx) } // client commands and options @@ -177,11 +181,11 @@ fn real_main() -> i32 { Ok(_) => 0, Err(_) => 1, } - }, + } // If nothing is specified, try to just use the config file instead // this could possibly become the way to configure most things // with most command line options being phased out - _ => cmd::server_command(None, node_config.unwrap()), + _ => cmd::server_command(None, node_config.unwrap(), logs_rx), } } diff --git a/src/bin/tui/constants.rs b/src/bin/tui/constants.rs index 0e6ae9cc5..07a074bcc 100644 --- a/src/bin/tui/constants.rs +++ b/src/bin/tui/constants.rs @@ -28,6 +28,9 @@ pub const SUBMENU_MINING_BUTTON: &str = "mining_submenu_button"; pub const TABLE_MINING_STATUS: &str = "mining_status_table"; pub const TABLE_MINING_DIFF_STATUS: &str = "mining_diff_status_table"; +// Logs View +pub const VIEW_LOGS: &str = "logs_view"; + // Mining View pub const VIEW_VERSION: &str = "version_view"; diff --git a/src/bin/tui/logs.rs b/src/bin/tui/logs.rs new file mode 100644 index 000000000..2b6bb982c --- /dev/null +++ b/src/bin/tui/logs.rs @@ -0,0 +1,104 @@ +// Copyright 2019 The Grin Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use cursive::theme::{BaseColor, Color, ColorStyle}; +use cursive::traits::Identifiable; +use cursive::view::View; +use cursive::views::BoxView; +use cursive::{Cursive, Printer}; + +use crate::tui::constants::VIEW_LOGS; +use cursive::utils::lines::spans::{LinesIterator, Row}; +use cursive::utils::markup::StyledString; +use grin_util::logger::LogEntry; +use log::Level; +use std::collections::VecDeque; + +pub struct TUILogsView; + +impl TUILogsView { + pub fn create() -> Box { + let logs_view = BoxView::with_full_screen(LogBufferView::new(200).with_id("logs")); + Box::new(logs_view.with_id(VIEW_LOGS)) + } + + pub fn update(c: &mut Cursive, entry: LogEntry) { + c.call_on_id("logs", |t: &mut LogBufferView| { + t.update(entry); + }); + } +} + +struct LogBufferView { + buffer: VecDeque, +} + +impl LogBufferView { + fn new(size: usize) -> Self { + let mut buffer = VecDeque::new(); + buffer.resize( + size, + LogEntry { + log: String::new(), + level: Level::Info, + }, + ); + + LogBufferView { buffer } + } + + fn update(&mut self, entry: LogEntry) { + self.buffer.push_front(entry); + self.buffer.pop_back(); + } + + fn color(level: Level) -> ColorStyle { + match level { + Level::Info => ColorStyle::new( + Color::Light(BaseColor::Green), + Color::Dark(BaseColor::Black), + ), + Level::Warn => ColorStyle::new( + Color::Light(BaseColor::Yellow), + Color::Dark(BaseColor::Black), + ), + Level::Error => { + ColorStyle::new(Color::Light(BaseColor::Red), Color::Dark(BaseColor::Black)) + } + _ => ColorStyle::new( + Color::Light(BaseColor::White), + Color::Dark(BaseColor::Black), + ), + } + } +} + +impl View for LogBufferView { + fn draw(&self, printer: &Printer) { + let mut i = 0; + for entry in self.buffer.iter().take(printer.size.y) { + printer.with_color(LogBufferView::color(entry.level), |p| { + let log_message = StyledString::plain(&entry.log); + let mut rows: Vec = LinesIterator::new(&log_message, printer.size.x).collect(); + rows.reverse(); // So stack traces are in the right order. + for row in rows { + for span in row.resolve(&log_message) { + p.print((0, p.size.y - 1 - i), span.content); + i += 1; + } + } + }); + } + } +} diff --git a/src/bin/tui/menu.rs b/src/bin/tui/menu.rs index e6aba230f..1ebc50974 100644 --- a/src/bin/tui/menu.rs +++ b/src/bin/tui/menu.rs @@ -25,8 +25,8 @@ use cursive::views::{ use cursive::Cursive; use crate::tui::constants::{ - MAIN_MENU, ROOT_STACK, SUBMENU_MINING_BUTTON, VIEW_BASIC_STATUS, VIEW_MINING, VIEW_PEER_SYNC, - VIEW_VERSION, + MAIN_MENU, ROOT_STACK, SUBMENU_MINING_BUTTON, VIEW_BASIC_STATUS, VIEW_LOGS, VIEW_MINING, + VIEW_PEER_SYNC, VIEW_VERSION, }; pub fn create() -> Box { @@ -38,6 +38,7 @@ pub fn create() -> Box { .get_mut() .add_item("Peers and Sync", VIEW_PEER_SYNC); main_menu.get_mut().add_item("Mining", VIEW_MINING); + main_menu.get_mut().add_item("Logs", VIEW_LOGS); main_menu.get_mut().add_item("Version Info", VIEW_VERSION); let change_view = |s: &mut Cursive, v: &&str| { if *v == "" { diff --git a/src/bin/tui/mod.rs b/src/bin/tui/mod.rs index ece0f3ef0..2d7fba244 100644 --- a/src/bin/tui/mod.rs +++ b/src/bin/tui/mod.rs @@ -17,6 +17,7 @@ use chrono; use humansize; // mod constants; +mod logs; mod menu; mod mining; mod peers; diff --git a/src/bin/tui/ui.rs b/src/bin/tui/ui.rs index f2daa15e5..b38f5ac2b 100644 --- a/src/bin/tui/ui.rs +++ b/src/bin/tui/ui.rs @@ -34,13 +34,15 @@ use crate::built_info; use crate::servers::Server; use crate::tui::constants::ROOT_STACK; use crate::tui::types::{TUIStatusListener, UIMessage}; -use crate::tui::{menu, mining, peers, status, version}; +use crate::tui::{logs, menu, mining, peers, status, version}; +use grin_util::logger::LogEntry; pub struct UI { cursive: Cursive, ui_rx: mpsc::Receiver, ui_tx: mpsc::Sender, controller_tx: mpsc::Sender, + logs_rx: mpsc::Receiver, } fn modify_theme(theme: &mut Theme) { @@ -57,19 +59,25 @@ fn modify_theme(theme: &mut Theme) { impl UI { /// Create a new UI - pub fn new(controller_tx: mpsc::Sender) -> UI { + pub fn new( + controller_tx: mpsc::Sender, + logs_rx: mpsc::Receiver, + ) -> UI { let (ui_tx, ui_rx) = mpsc::channel::(); + let mut grin_ui = UI { cursive: Cursive::default(), - ui_tx: ui_tx, - ui_rx: ui_rx, - controller_tx: controller_tx, + ui_tx, + ui_rx, + controller_tx, + logs_rx, }; // Create UI objects, etc let status_view = status::TUIStatusView::create(); let mining_view = mining::TUIMiningView::create(); let peer_view = peers::TUIPeerView::create(); + let logs_view = logs::TUILogsView::create(); let version_view = version::TUIVersionView::create(); let main_menu = menu::create(); @@ -78,6 +86,7 @@ impl UI { .layer(version_view) .layer(mining_view) .layer(peer_view) + .layer(logs_view) .layer(status_view) .with_id(ROOT_STACK) .full_height(); @@ -128,6 +137,10 @@ impl UI { return false; } + while let Some(message) = self.logs_rx.try_iter().next() { + logs::TUILogsView::update(&mut self.cursive, message); + } + // Process any pending UI messages while let Some(message) = self.ui_rx.try_iter().next() { match message { @@ -162,13 +175,14 @@ pub enum ControllerMessage { impl Controller { /// Create a new controller - pub fn new() -> Result { + pub fn new(logs_rx: mpsc::Receiver) -> Result { let (tx, rx) = mpsc::channel::(); Ok(Controller { - rx: rx, - ui: UI::new(tx), + rx, + ui: UI::new(tx, logs_rx), }) } + /// Run the controller pub fn run(&mut self, server: Server) { let stat_update_interval = 1; @@ -177,6 +191,7 @@ impl Controller { while let Some(message) = self.rx.try_iter().next() { match message { ControllerMessage::Shutdown => { + warn!("Shutdown in progress, please wait"); self.ui.stop(); server.stop(); return; diff --git a/util/src/lib.rs b/util/src/lib.rs index 1da379b82..4fb62b261 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -43,7 +43,7 @@ pub mod secp_static; pub use crate::secp_static::static_secp_instance; pub mod types; -pub use crate::types::{LogLevel, LoggingConfig, ZeroingString}; +pub use crate::types::ZeroingString; pub mod macros; diff --git a/util/src/logger.rs b/util/src/logger.rs index e800c44ff..3a93aee63 100644 --- a/util/src/logger.rs +++ b/util/src/logger.rs @@ -18,9 +18,7 @@ use std::ops::Deref; use backtrace::Backtrace; use std::{panic, thread}; -use crate::types::{self, LogLevel, LoggingConfig}; - -use log::{LevelFilter, Record}; +use log::{Level, Record}; use log4rs; use log4rs::append::console::ConsoleAppender; use log4rs::append::file::FileAppender; @@ -32,17 +30,12 @@ use log4rs::append::rolling_file::{ use log4rs::append::Append; use log4rs::config::{Appender, Config, Root}; use log4rs::encode::pattern::PatternEncoder; +use log4rs::encode::writer::simple::SimpleWriter; +use log4rs::encode::Encode; use log4rs::filter::{threshold::ThresholdFilter, Filter, Response}; - -fn convert_log_level(in_level: &LogLevel) -> LevelFilter { - match *in_level { - LogLevel::Info => LevelFilter::Info, - LogLevel::Warning => LevelFilter::Warn, - LogLevel::Debug => LevelFilter::Debug, - LogLevel::Trace => LevelFilter::Trace, - LogLevel::Error => LevelFilter::Error, - } -} +use std::error::Error; +use std::sync::mpsc; +use std::sync::mpsc::SyncSender; lazy_static! { /// Flag to observe whether logging was explicitly initialised (don't output otherwise) @@ -56,6 +49,57 @@ lazy_static! { const LOGGING_PATTERN: &str = "{d(%Y%m%d %H:%M:%S%.3f)} {h({l})} {M} - {m}{n}"; +/// 32 log files to rotate over by default +const DEFAULT_ROTATE_LOG_FILES: u32 = 32 as u32; + +/// Log Entry +#[derive(Clone, Serialize, Debug)] +pub struct LogEntry { + /// The log message + pub log: String, + /// The log levelO + pub level: Level, +} + +/// Logging config +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct LoggingConfig { + /// whether to log to stdout + pub log_to_stdout: bool, + /// logging level for stdout + pub stdout_log_level: Level, + /// whether to log to file + pub log_to_file: bool, + /// log file level + pub file_log_level: Level, + /// Log file path + pub log_file_path: String, + /// Whether to append to log or replace + pub log_file_append: bool, + /// Size of the log in bytes to rotate over (optional) + pub log_max_size: Option, + /// Number of the log files to rotate over (optional) + pub log_max_files: Option, + /// Whether the tui is running (optional) + pub tui_running: Option, +} + +impl Default for LoggingConfig { + fn default() -> LoggingConfig { + LoggingConfig { + log_to_stdout: true, + stdout_log_level: Level::Warn, + log_to_file: true, + file_log_level: Level::Info, + log_file_path: String::from("grin.log"), + log_file_append: true, + log_max_size: Some(1024 * 1024 * 16), // 16 megabytes default + log_max_files: Some(DEFAULT_ROTATE_LOG_FILES), + tui_running: None, + } + } +} + /// This filter is rejecting messages that doesn't start with "grin" /// in order to save log space for only Grin-related records #[derive(Debug)] @@ -73,8 +117,32 @@ impl Filter for GrinFilter { } } +#[derive(Debug)] +struct ChannelAppender { + output: Mutex>, + encoder: Box, +} + +impl Append for ChannelAppender { + fn append(&self, record: &Record) -> Result<(), Box> { + let mut writer = SimpleWriter(Vec::new()); + self.encoder.encode(&mut writer, record)?; + + let log = String::from_utf8_lossy(writer.0.as_slice()).to_string(); + + let _ = self.output.lock().try_send(LogEntry { + log, + level: record.level(), + }); + + Ok(()) + } + + fn flush(&self) {} +} + /// Initialize the logger with the given configuration -pub fn init_logger(config: Option) { +pub fn init_logger(config: Option, logs_tx: Option>) { if let Some(c) = config { let tui_running = c.tui_running.unwrap_or(false); if tui_running { @@ -86,8 +154,8 @@ pub fn init_logger(config: Option) { let mut config_ref = LOGGING_CONFIG.lock(); *config_ref = c.clone(); - let level_stdout = convert_log_level(&c.stdout_log_level); - let level_file = convert_log_level(&c.file_log_level); + let level_stdout = c.stdout_log_level.to_level_filter(); + let level_file = c.file_log_level.to_level_filter(); // Determine minimum logging level for Root logger let level_minimum = if level_stdout > level_file { @@ -105,15 +173,26 @@ pub fn init_logger(config: Option) { let mut appenders = vec![]; - if c.log_to_stdout && !tui_running { - let filter = Box::new(ThresholdFilter::new(level_stdout)); + if tui_running { + let channel_appender = ChannelAppender { + encoder: Box::new(PatternEncoder::new(&LOGGING_PATTERN)), + output: Mutex::new(logs_tx.unwrap()), + }; + appenders.push( Appender::builder() - .filter(filter) + .filter(Box::new(ThresholdFilter::new(level_stdout))) + .filter(Box::new(GrinFilter)) + .build("tui", Box::new(channel_appender)), + ); + root = root.appender("tui"); + } else if c.log_to_stdout { + appenders.push( + Appender::builder() + .filter(Box::new(ThresholdFilter::new(level_stdout))) .filter(Box::new(GrinFilter)) .build("stdout", Box::new(stdout)), ); - root = root.appender("stdout"); } @@ -123,9 +202,7 @@ pub fn init_logger(config: Option) { let filter = Box::new(ThresholdFilter::new(level_file)); let file: Box = { if let Some(size) = c.log_max_size { - let count = c - .log_max_files - .unwrap_or_else(|| types::DEFAULT_ROTATE_LOG_FILES); + let count = c.log_max_files.unwrap_or_else(|| DEFAULT_ROTATE_LOG_FILES); let roller = FixedWindowRoller::builder() .build(&format!("{}.{{}}.gz", c.log_file_path), count) .unwrap(); @@ -188,13 +265,13 @@ pub fn init_test_logger() { } let mut logger = LoggingConfig::default(); logger.log_to_file = false; - logger.stdout_log_level = LogLevel::Debug; + logger.stdout_log_level = Level::Debug; // Save current logging configuration let mut config_ref = LOGGING_CONFIG.lock(); *config_ref = logger; - let level_stdout = convert_log_level(&config_ref.stdout_log_level); + let level_stdout = config_ref.stdout_log_level.to_level_filter(); let level_minimum = level_stdout; // minimum logging level for Root logger // Start logger diff --git a/util/src/types.rs b/util/src/types.rs index ed7788e8e..770af6ad9 100644 --- a/util/src/types.rs +++ b/util/src/types.rs @@ -12,64 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Logging configuration types - -/// Log level types -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub enum LogLevel { - /// Error - Error, - /// Warning - Warning, - /// Info - Info, - /// Debug - Debug, - /// Trace - Trace, -} - -/// 32 log files to rotate over by default -pub const DEFAULT_ROTATE_LOG_FILES: u32 = 32 as u32; - -/// Logging config -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct LoggingConfig { - /// whether to log to stdout - pub log_to_stdout: bool, - /// logging level for stdout - pub stdout_log_level: LogLevel, - /// whether to log to file - pub log_to_file: bool, - /// log file level - pub file_log_level: LogLevel, - /// Log file path - pub log_file_path: String, - /// Whether to append to log or replace - pub log_file_append: bool, - /// Size of the log in bytes to rotate over (optional) - pub log_max_size: Option, - /// Number of the log files to rotate over (optional) - pub log_max_files: Option, - /// Whether the tui is running (optional) - pub tui_running: Option, -} - -impl Default for LoggingConfig { - fn default() -> LoggingConfig { - LoggingConfig { - log_to_stdout: true, - stdout_log_level: LogLevel::Warning, - log_to_file: true, - file_log_level: LogLevel::Info, - log_file_path: String::from("grin.log"), - log_file_append: true, - log_max_size: Some(1024 * 1024 * 16), // 16 megabytes default - log_max_files: Some(DEFAULT_ROTATE_LOG_FILES), - tui_running: None, - } - } -} +//! Zeroing String use std::ops::Deref; use zeroize::Zeroize;