mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-25 14:05:41 -05:00
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.
This commit is contained in:
parent
26746b4421
commit
1e80a2e757
6 changed files with 114 additions and 63 deletions
|
@ -49,12 +49,12 @@ image = "0.20.1"
|
||||||
static_assertions = "0.2.5"
|
static_assertions = "0.2.5"
|
||||||
terminfo = "0.6.1"
|
terminfo = "0.6.1"
|
||||||
url = "1.7.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]
|
[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))'.dependencies]
|
||||||
x11-dl = "2"
|
x11-dl = "2"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
tempfile = "3.0.4"
|
||||||
winpty = { path = "./winpty" }
|
winpty = { path = "./winpty" }
|
||||||
mio-named-pipes = "0.1"
|
mio-named-pipes = "0.1"
|
||||||
winapi = { version = "0.3.5", features = ["winuser", "synchapi", "roerrorapi", "winerror"]}
|
winapi = { version = "0.3.5", features = ["winuser", "synchapi", "roerrorapi", "winerror"]}
|
||||||
|
|
|
@ -28,7 +28,7 @@ use renderer::{self, GlyphCache, QuadRenderer};
|
||||||
use term::{Term, SizeInfo, RenderableCell};
|
use term::{Term, SizeInfo, RenderableCell};
|
||||||
use sync::FairMutex;
|
use sync::FairMutex;
|
||||||
use window::{self, Window};
|
use window::{self, Window};
|
||||||
use logging;
|
use logging::LoggerProxy;
|
||||||
use Rgb;
|
use Rgb;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -100,6 +100,7 @@ pub struct Display {
|
||||||
meter: Meter,
|
meter: Meter,
|
||||||
font_size: font::Size,
|
font_size: font::Size,
|
||||||
size_info: SizeInfo,
|
size_info: SizeInfo,
|
||||||
|
logger_proxy: LoggerProxy,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Can wakeup the render loop from other threads
|
/// Can wakeup the render loop from other threads
|
||||||
|
@ -130,7 +131,11 @@ impl Display {
|
||||||
&self.size_info
|
&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
|
// Extract some properties from config
|
||||||
let render_timer = config.render_timer();
|
let render_timer = config.render_timer();
|
||||||
|
|
||||||
|
@ -210,6 +215,7 @@ impl Display {
|
||||||
meter: Meter::new(),
|
meter: Meter::new(),
|
||||||
font_size: font::Size::new(0.),
|
font_size: font::Size::new(0.),
|
||||||
size_info,
|
size_info,
|
||||||
|
logger_proxy,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,8 +409,8 @@ impl Display {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display errors and warnings
|
// Display errors and warnings
|
||||||
if logging::errors() {
|
if self.logger_proxy.errors() {
|
||||||
let msg = " ERROR: Full log at /tmp/alacritty-todo.log ";
|
let msg = format!(" ERROR: Full log at {} ", self.logger_proxy.log_path());
|
||||||
let color = Rgb {
|
let color = Rgb {
|
||||||
r: 0xff,
|
r: 0xff,
|
||||||
g: 0x00,
|
g: 0x00,
|
||||||
|
@ -413,8 +419,8 @@ impl Display {
|
||||||
self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
|
self.renderer.with_api(config, &size_info, visual_bell_intensity, |mut api| {
|
||||||
api.render_string(&msg, size_info.lines() - 1, glyph_cache, color);
|
api.render_string(&msg, size_info.lines() - 1, glyph_cache, color);
|
||||||
});
|
});
|
||||||
} else if logging::warnings() {
|
} else if self.logger_proxy.warnings() {
|
||||||
let msg = " WARNING: Full log at /tmp/alacritty-todo.log ";
|
let msg = format!(" WARNING: Full log at {} ", self.logger_proxy.log_path());
|
||||||
let color = Rgb {
|
let color = Rgb {
|
||||||
r: 0xff,
|
r: 0xff,
|
||||||
g: 0xff,
|
g: 0xff,
|
||||||
|
|
|
@ -64,7 +64,6 @@ extern crate xdg;
|
||||||
extern crate base64;
|
extern crate base64;
|
||||||
extern crate terminfo;
|
extern crate terminfo;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
extern crate tempfile;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
127
src/logging.rs
127
src/logging.rs
|
@ -19,55 +19,82 @@
|
||||||
//! log-level is sufficient for the level configured in `cli::Options`.
|
//! log-level is sufficient for the level configured in `cli::Options`.
|
||||||
use cli;
|
use cli;
|
||||||
use log::{self, Level};
|
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::io::{self, LineWriter, Stdout, Write};
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Mutex;
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
static ERRORS: AtomicBool = AtomicBool::new(false);
|
const LOG_FILE_NAME: &'static str = "Alacritty.log";
|
||||||
static WARNINGS: AtomicBool = AtomicBool::new(false);
|
|
||||||
|
|
||||||
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 env_logger if RUST_LOG environment variable is defined. Otherwise,
|
||||||
// use the alacritty-only logger.
|
// use the alacritty-only logger.
|
||||||
if ::std::env::var("RUST_LOG").is_ok() {
|
if ::std::env::var("RUST_LOG").is_ok() {
|
||||||
::env_logger::try_init()
|
::env_logger::try_init()?;
|
||||||
|
Ok(LoggerProxy::default())
|
||||||
} else {
|
} 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 {
|
/// Proxy object for bidirectional communicating with the global logger.
|
||||||
WARNINGS.load(Ordering::Relaxed)
|
#[derive(Clone, Default)]
|
||||||
|
pub struct LoggerProxy {
|
||||||
|
errors: Arc<AtomicBool>,
|
||||||
|
warnings: Arc<AtomicBool>,
|
||||||
|
log_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn errors() -> bool {
|
impl LoggerProxy {
|
||||||
ERRORS.load(Ordering::Relaxed)
|
/// Check for new logged errors.
|
||||||
|
pub fn errors(&self) -> bool {
|
||||||
|
self.errors.load(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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 fn clear_errors() {
|
struct Logger {
|
||||||
ERRORS.store(false, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_warnings() {
|
|
||||||
WARNINGS.store(false, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Logger {
|
|
||||||
level: log::LevelFilter,
|
level: log::LevelFilter,
|
||||||
logfile: Mutex<OnDemandTempFile>,
|
logfile: Mutex<OnDemandLogFile>,
|
||||||
stdout: Mutex<LineWriter<Stdout>>,
|
stdout: Mutex<LineWriter<Stdout>>,
|
||||||
|
errors: Arc<AtomicBool>,
|
||||||
|
warnings: Arc<AtomicBool>,
|
||||||
|
log_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Logger {
|
impl Logger {
|
||||||
// False positive, see: https://github.com/rust-lang-nursery/rust-clippy/issues/734
|
// False positive, see: https://github.com/rust-lang-nursery/rust-clippy/issues/734
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(new_ret_no_self))]
|
#[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);
|
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()));
|
let stdout = Mutex::new(LineWriter::new(io::stdout()));
|
||||||
|
|
||||||
|
@ -75,6 +102,17 @@ impl Logger {
|
||||||
level,
|
level,
|
||||||
logfile,
|
logfile,
|
||||||
stdout,
|
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() {
|
match record.level() {
|
||||||
Level::Error => ERRORS.store(true, Ordering::Relaxed),
|
Level::Error => self.errors.store(true, Ordering::Relaxed),
|
||||||
Level::Warn => WARNINGS.store(true, Ordering::Relaxed),
|
Level::Warn => self.warnings.store(true, Ordering::Relaxed),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,37 +143,38 @@ impl log::Log for Logger {
|
||||||
fn flush(&self) {}
|
fn flush(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OnDemandTempFile {
|
struct OnDemandLogFile {
|
||||||
file: Option<LineWriter<File>>,
|
file: Option<LineWriter<File>>,
|
||||||
prefix: String,
|
path: PathBuf,
|
||||||
suffix: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OnDemandTempFile {
|
impl OnDemandLogFile {
|
||||||
fn new<T: Into<String>, J: Into<String>>(prefix: T, suffix: J) -> Self {
|
fn new() -> Self {
|
||||||
OnDemandTempFile {
|
let mut path = env::temp_dir();
|
||||||
file: None,
|
path.push(LOG_FILE_NAME);
|
||||||
prefix: prefix.into(),
|
|
||||||
suffix: suffix.into(),
|
OnDemandLogFile { file: None, path }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&mut self) -> Result<&mut LineWriter<File>, io::Error> {
|
fn file(&mut self) -> Result<&mut LineWriter<File>, io::Error> {
|
||||||
if self.file.is_none() {
|
if self.file.is_none() {
|
||||||
let file = tempfile::Builder::new()
|
let file = OpenOptions::new()
|
||||||
.prefix(&self.prefix)
|
.append(true)
|
||||||
.suffix(&self.suffix)
|
.create(true)
|
||||||
.tempfile()?;
|
.open(&self.path)?;
|
||||||
let path = file.path().to_owned();
|
self.file = Some(io::LineWriter::new(file));
|
||||||
self.file = Some(io::LineWriter::new(file.persist(&path)?));
|
println!("Created log file at {:?}", self.path);
|
||||||
println!("Created log file at {:?}", path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.file.as_mut().unwrap())
|
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> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
|
||||||
self.file()?.write(buf)
|
self.file()?.write(buf)
|
||||||
}
|
}
|
||||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -52,7 +52,7 @@ use alacritty::event;
|
||||||
use alacritty::event_loop::{self, EventLoop, Msg};
|
use alacritty::event_loop::{self, EventLoop, Msg};
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use alacritty::locale;
|
use alacritty::locale;
|
||||||
use alacritty::logging;
|
use alacritty::logging::{self, LoggerProxy};
|
||||||
use alacritty::sync::FairMutex;
|
use alacritty::sync::FairMutex;
|
||||||
use alacritty::term::Term;
|
use alacritty::term::Term;
|
||||||
use alacritty::tty::{self, process_should_exit};
|
use alacritty::tty::{self, process_should_exit};
|
||||||
|
@ -69,7 +69,7 @@ fn main() {
|
||||||
let options = cli::Options::load();
|
let options = cli::Options::load();
|
||||||
|
|
||||||
// Initialize the logger as soon as possible as to capture output from other subsystems
|
// 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
|
// Load configuration file
|
||||||
let config = load_config(&options).update_dynamic_title(&options);
|
let config = load_config(&options).update_dynamic_title(&options);
|
||||||
|
@ -82,7 +82,7 @@ fn main() {
|
||||||
locale::set_locale_environment();
|
locale::set_locale_environment();
|
||||||
|
|
||||||
// Run alacritty
|
// 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));
|
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,
|
/// Creates a window, the terminal state, pty, I/O event loop, input processor,
|
||||||
/// config change monitor, and runs the main display loop.
|
/// 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.");
|
info!("Welcome to Alacritty.");
|
||||||
if let Some(config_path) = config.path() {
|
if let Some(config_path) = config.path() {
|
||||||
info!("Configuration loaded from {}", config_path.display());
|
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.
|
// Create a display.
|
||||||
//
|
//
|
||||||
// The display manages a window and can draw the terminal
|
// 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!(
|
info!(
|
||||||
"PTY Dimensions: {:?} x {:?}",
|
"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
|
// 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
|
// wrapped in a clonable mutex since both the I/O loop and display need to
|
||||||
// access it.
|
// 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));
|
let terminal = Arc::new(FairMutex::new(terminal));
|
||||||
|
|
||||||
// Find the window ID for setting $WINDOWID
|
// Find the window ID for setting $WINDOWID
|
||||||
|
|
|
@ -31,7 +31,7 @@ use config::{Config, VisualBellAnimation};
|
||||||
use {MouseCursor, Rgb};
|
use {MouseCursor, Rgb};
|
||||||
use copypasta::{Clipboard, Load, Store};
|
use copypasta::{Clipboard, Load, Store};
|
||||||
use input::FONT_SIZE_STEP;
|
use input::FONT_SIZE_STEP;
|
||||||
use logging;
|
use logging::LoggerProxy;
|
||||||
|
|
||||||
pub mod cell;
|
pub mod cell;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
@ -811,6 +811,9 @@ pub struct Term {
|
||||||
|
|
||||||
/// Automatically scroll to bottom when new lines are added
|
/// Automatically scroll to bottom when new lines are added
|
||||||
auto_scroll: bool,
|
auto_scroll: bool,
|
||||||
|
|
||||||
|
/// Proxy object for clearing displayed errors and warnings
|
||||||
|
logger_proxy: LoggerProxy,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Terminal size info
|
/// Terminal size info
|
||||||
|
@ -893,7 +896,7 @@ impl Term {
|
||||||
self.next_mouse_cursor.take()
|
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_cols = size.cols();
|
||||||
let num_lines = size.lines();
|
let num_lines = size.lines();
|
||||||
|
|
||||||
|
@ -937,6 +940,7 @@ impl Term {
|
||||||
dynamic_title: config.dynamic_title(),
|
dynamic_title: config.dynamic_title(),
|
||||||
tabspaces,
|
tabspaces,
|
||||||
auto_scroll: config.scrolling().auto_scroll,
|
auto_scroll: config.scrolling().auto_scroll,
|
||||||
|
logger_proxy,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1823,9 +1827,8 @@ impl ansi::Handler for Term {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ansi::ClearMode::All => {
|
ansi::ClearMode::All => {
|
||||||
// Clear errors and warnings
|
// Clear displayed errors and warnings
|
||||||
logging::clear_errors();
|
self.logger_proxy.clear();
|
||||||
logging::clear_warnings();
|
|
||||||
|
|
||||||
self.grid.region_mut(..).each(|c| c.reset(&template));
|
self.grid.region_mut(..).each(|c| c.reset(&template));
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue