diff options
author | Christian Duerr <contact@christianduerr.com> | 2018-11-07 23:41:42 +0100 |
---|---|---|
committer | Christian Duerr <contact@christianduerr.com> | 2018-11-10 18:18:59 +0100 |
commit | 1e80a2e757134e602400c8d925558c986e3555d1 (patch) | |
tree | cdd1f6166fcd8d0d51184d031d02add8fca7fbf8 | |
parent | 26746b4421bee93ebbed9d63d468e8105ede3f06 (diff) | |
download | alacritty-1e80a2e757134e602400c8d925558c986e3555d1.tar.gz alacritty-1e80a2e757134e602400c8d925558c986e3555d1.zip |
Display log path
When an error or warning is shown, it now correctly points to the log
file where the error has been written to.
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/display.rs | 18 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/logging.rs | 123 | ||||
-rw-r--r-- | src/main.rs | 16 | ||||
-rw-r--r-- | src/term/mod.rs | 13 |
6 files changed, 112 insertions, 61 deletions
@@ -49,12 +49,12 @@ image = "0.20.1" static_assertions = "0.2.5" terminfo = "0.6.1" url = "1.7.1" -tempfile = "3.0.4" [target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))'.dependencies] x11-dl = "2" [target.'cfg(windows)'.dependencies] +tempfile = "3.0.4" winpty = { path = "./winpty" } mio-named-pipes = "0.1" winapi = { version = "0.3.5", features = ["winuser", "synchapi", "roerrorapi", "winerror"]} diff --git a/src/display.rs b/src/display.rs index b185b6be..eb37dc54 100644 --- a/src/display.rs +++ b/src/display.rs @@ -28,7 +28,7 @@ use renderer::{self, GlyphCache, QuadRenderer}; use term::{Term, SizeInfo, RenderableCell}; use sync::FairMutex; use window::{self, Window}; -use logging; +use logging::LoggerProxy; use Rgb; #[derive(Debug)] @@ -100,6 +100,7 @@ pub struct Display { meter: Meter, font_size: font::Size, size_info: SizeInfo, + logger_proxy: LoggerProxy, } /// Can wakeup the render loop from other threads @@ -130,7 +131,11 @@ impl Display { &self.size_info } - pub fn new(config: &Config, options: &cli::Options) -> Result<Display, Error> { + pub fn new( + config: &Config, + options: &cli::Options, + logger_proxy: LoggerProxy + ) -> Result<Display, Error> { // Extract some properties from config let render_timer = config.render_timer(); @@ -210,6 +215,7 @@ impl Display { meter: Meter::new(), font_size: font::Size::new(0.), size_info, + logger_proxy, }) } @@ -403,8 +409,8 @@ impl Display { } // Display errors and warnings - if logging::errors() { - let msg = " ERROR: Full log at /tmp/alacritty-todo.log "; + if self.logger_proxy.errors() { + let msg = format!(" ERROR: Full log at {} ", self.logger_proxy.log_path()); let color = Rgb { r: 0xff, g: 0x00, @@ -413,8 +419,8 @@ impl Display { self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| { api.render_string(&msg, size_info.lines() - 1, glyph_cache, color); }); - } else if logging::warnings() { - let msg = " WARNING: Full log at /tmp/alacritty-todo.log "; + } else if self.logger_proxy.warnings() { + let msg = format!(" WARNING: Full log at {} ", self.logger_proxy.log_path()); let color = Rgb { r: 0xff, g: 0xff, @@ -64,7 +64,6 @@ extern crate xdg; extern crate base64; extern crate terminfo; extern crate url; -extern crate tempfile; #[macro_use] pub mod macros; diff --git a/src/logging.rs b/src/logging.rs index 6b43c2a7..d10c9579 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -19,55 +19,82 @@ //! log-level is sufficient for the level configured in `cli::Options`. use cli; use log::{self, Level}; -use tempfile; -use std::fs::File; +use std::borrow::Cow; +use std::env; +use std::fs::{File, OpenOptions}; use std::io::{self, LineWriter, Stdout, Write}; +use std::path::PathBuf; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; -static ERRORS: AtomicBool = AtomicBool::new(false); -static WARNINGS: AtomicBool = AtomicBool::new(false); +const LOG_FILE_NAME: &'static str = "Alacritty.log"; -pub fn initialize(options: &cli::Options) -> Result<(), log::SetLoggerError> { +pub fn initialize(options: &cli::Options) -> Result<LoggerProxy, log::SetLoggerError> { // Use env_logger if RUST_LOG environment variable is defined. Otherwise, // use the alacritty-only logger. if ::std::env::var("RUST_LOG").is_ok() { - ::env_logger::try_init() + ::env_logger::try_init()?; + Ok(LoggerProxy::default()) } else { - log::set_boxed_logger(Box::new(Logger::new(options.log_level))) + let logger = Logger::new(options.log_level); + let proxy = logger.proxy(); + + log::set_boxed_logger(Box::new(logger))?; + + Ok(proxy) } } -pub fn warnings() -> bool { - WARNINGS.load(Ordering::Relaxed) +/// Proxy object for bidirectional communicating with the global logger. +#[derive(Clone, Default)] +pub struct LoggerProxy { + errors: Arc<AtomicBool>, + warnings: Arc<AtomicBool>, + log_path: String, } -pub fn errors() -> bool { - ERRORS.load(Ordering::Relaxed) -} +impl LoggerProxy { + /// Check for new logged errors. + pub fn errors(&self) -> bool { + self.errors.load(Ordering::Relaxed) + } -pub fn clear_errors() { - ERRORS.store(false, Ordering::Relaxed); -} + /// Check for new logged warnings. + pub fn warnings(&self) -> bool { + self.warnings.load(Ordering::Relaxed) + } + + /// Get the path of the log file. + pub fn log_path(&self) -> &str { + &self.log_path + } -pub fn clear_warnings() { - WARNINGS.store(false, Ordering::Relaxed); + /// Clear log warnings/errors from the Alacritty UI. + pub fn clear(&mut self) { + self.errors.store(false, Ordering::Relaxed); + self.warnings.store(false, Ordering::Relaxed); + } } -pub struct Logger { +struct Logger { level: log::LevelFilter, - logfile: Mutex<OnDemandTempFile>, + logfile: Mutex<OnDemandLogFile>, stdout: Mutex<LineWriter<Stdout>>, + errors: Arc<AtomicBool>, + warnings: Arc<AtomicBool>, + log_path: String, } impl Logger { // False positive, see: https://github.com/rust-lang-nursery/rust-clippy/issues/734 #[cfg_attr(feature = "cargo-clippy", allow(new_ret_no_self))] - pub fn new(level: log::LevelFilter) -> Self { + fn new(level: log::LevelFilter) -> Self { log::set_max_level(level); - let logfile = Mutex::new(OnDemandTempFile::new("alacritty", String::from(".log"))); + let logfile = OnDemandLogFile::new(); + let log_path = logfile.path().to_string(); + let logfile = Mutex::new(logfile); let stdout = Mutex::new(LineWriter::new(io::stdout())); @@ -75,6 +102,17 @@ impl Logger { level, logfile, stdout, + log_path, + errors: Arc::new(AtomicBool::new(false)), + warnings: Arc::new(AtomicBool::new(false)), + } + } + + fn proxy(&self) -> LoggerProxy { + LoggerProxy { + errors: self.errors.clone(), + warnings: self.warnings.clone(), + log_path: self.log_path.clone(), } } } @@ -95,8 +133,8 @@ impl log::Log for Logger { } match record.level() { - Level::Error => ERRORS.store(true, Ordering::Relaxed), - Level::Warn => WARNINGS.store(true, Ordering::Relaxed), + Level::Error => self.errors.store(true, Ordering::Relaxed), + Level::Warn => self.warnings.store(true, Ordering::Relaxed), _ => (), } } @@ -105,37 +143,38 @@ impl log::Log for Logger { fn flush(&self) {} } -struct OnDemandTempFile { +struct OnDemandLogFile { file: Option<LineWriter<File>>, - prefix: String, - suffix: String, + path: PathBuf, } -impl OnDemandTempFile { - fn new<T: Into<String>, J: Into<String>>(prefix: T, suffix: J) -> Self { - OnDemandTempFile { - file: None, - prefix: prefix.into(), - suffix: suffix.into(), - } +impl OnDemandLogFile { + fn new() -> Self { + let mut path = env::temp_dir(); + path.push(LOG_FILE_NAME); + + OnDemandLogFile { file: None, path } } fn file(&mut self) -> Result<&mut LineWriter<File>, io::Error> { if self.file.is_none() { - let file = tempfile::Builder::new() - .prefix(&self.prefix) - .suffix(&self.suffix) - .tempfile()?; - let path = file.path().to_owned(); - self.file = Some(io::LineWriter::new(file.persist(&path)?)); - println!("Created log file at {:?}", path); + let file = OpenOptions::new() + .append(true) + .create(true) + .open(&self.path)?; + self.file = Some(io::LineWriter::new(file)); + println!("Created log file at {:?}", self.path); } Ok(self.file.as_mut().unwrap()) } + + fn path(&self) -> Cow<str> { + self.path.to_string_lossy() + } } -impl Write for OnDemandTempFile { +impl Write for OnDemandLogFile { fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> { self.file()?.write(buf) } diff --git a/src/main.rs b/src/main.rs index bdb401fc..1498c14a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,7 +52,7 @@ use alacritty::event; use alacritty::event_loop::{self, EventLoop, Msg}; #[cfg(target_os = "macos")] use alacritty::locale; -use alacritty::logging; +use alacritty::logging::{self, LoggerProxy}; use alacritty::sync::FairMutex; use alacritty::term::Term; use alacritty::tty::{self, process_should_exit}; @@ -69,7 +69,7 @@ fn main() { let options = cli::Options::load(); // Initialize the logger as soon as possible as to capture output from other subsystems - logging::initialize(&options).expect("Unable to initialize logger"); + let logger_proxy = logging::initialize(&options).expect("Unable to initialize logger"); // Load configuration file let config = load_config(&options).update_dynamic_title(&options); @@ -82,7 +82,7 @@ fn main() { locale::set_locale_environment(); // Run alacritty - if let Err(err) = run(config, &options) { + if let Err(err) = run(config, &options, logger_proxy) { die!("Alacritty encountered an unrecoverable error:\n\n\t{}\n", Red(err)); } @@ -112,7 +112,11 @@ fn load_config(options: &cli::Options) -> Config { /// /// Creates a window, the terminal state, pty, I/O event loop, input processor, /// config change monitor, and runs the main display loop. -fn run(mut config: Config, options: &cli::Options) -> Result<(), Box<Error>> { +fn run( + mut config: Config, + options: &cli::Options, + logger_proxy: LoggerProxy, +) -> Result<(), Box<Error>> { info!("Welcome to Alacritty."); if let Some(config_path) = config.path() { info!("Configuration loaded from {}", config_path.display()); @@ -121,7 +125,7 @@ fn run(mut config: Config, options: &cli::Options) -> Result<(), Box<Error>> { // Create a display. // // The display manages a window and can draw the terminal - let mut display = Display::new(&config, options)?; + let mut display = Display::new(&config, options, logger_proxy.clone())?; info!( "PTY Dimensions: {:?} x {:?}", @@ -134,7 +138,7 @@ fn run(mut config: Config, options: &cli::Options) -> Result<(), Box<Error>> { // This object contains all of the state about what's being displayed. It's // wrapped in a clonable mutex since both the I/O loop and display need to // access it. - let terminal = Term::new(&config, display.size().to_owned()); + let terminal = Term::new(&config, display.size().to_owned(), logger_proxy); let terminal = Arc::new(FairMutex::new(terminal)); // Find the window ID for setting $WINDOWID diff --git a/src/term/mod.rs b/src/term/mod.rs index 8663a073..b47e6dcb 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -31,7 +31,7 @@ use config::{Config, VisualBellAnimation}; use {MouseCursor, Rgb}; use copypasta::{Clipboard, Load, Store}; use input::FONT_SIZE_STEP; -use logging; +use logging::LoggerProxy; pub mod cell; pub mod color; @@ -811,6 +811,9 @@ pub struct Term { /// Automatically scroll to bottom when new lines are added auto_scroll: bool, + + /// Proxy object for clearing displayed errors and warnings + logger_proxy: LoggerProxy, } /// Terminal size info @@ -893,7 +896,7 @@ impl Term { self.next_mouse_cursor.take() } - pub fn new(config: &Config, size: SizeInfo) -> Term { + pub fn new(config: &Config, size: SizeInfo, logger_proxy: LoggerProxy) -> Term { let num_cols = size.cols(); let num_lines = size.lines(); @@ -937,6 +940,7 @@ impl Term { dynamic_title: config.dynamic_title(), tabspaces, auto_scroll: config.scrolling().auto_scroll, + logger_proxy, } } @@ -1823,9 +1827,8 @@ impl ansi::Handler for Term { } }, ansi::ClearMode::All => { - // Clear errors and warnings - logging::clear_errors(); - logging::clear_warnings(); + // Clear displayed errors and warnings + self.logger_proxy.clear(); self.grid.region_mut(..).each(|c| c.reset(&template)); }, |