有什么办法可以做到这一点吗?在终端图形库中,如果发生异常,异常将在显示之前被刷新,这使得使用该库进行编程非常困难。
impl Drop for Terminal {
fn drop(&mut self) {
self.outbuffer.write_all(&self.driver.get(DevFn::ShowCursor)).unwrap();
self.outbuffer.write_all(&self.driver.get(DevFn::Reset)).unwrap();
self.outbuffer.write_all(&self.driver.get(DevFn::Clear)).unwrap();
self.outbuffer.write_all(&self.driver.get(DevFn::ExitCa)).unwrap();
self.flush().unwrap(); // If an exception occurs, this will reclear the screen and remove the output
self.termctl.reset().unwrap();
SIGWINCH_STATUS.store(false, Ordering::SeqCst);
RUSTTY_STATUS.store(false, Ordering::SeqCst);
}
}
Run Code Online (Sandbox Code Playgroud)
如果我要注释掉self.flush().unwrap();异常,则会打印异常,但是即使程序结束后,终端也不会正确刷新屏幕并在终端上留下图形。
是否可以在程序开始时指定用于写入的自定义缓冲区恐慌?或者可能写一个黑客技巧来做到这一点?这样,在刷新之后,我们可以检查该缓冲区内是否有任何内容,如果有,我们就知道发生了异常并可以将其打印出来。
然而,通过注释掉self.flush().unwrap();,我们看到了实际的异常,但现在是一个非常丑陋的终端。该解决方案将不起作用,因为正确执行的程序仍然需要刷新,因为不需要显示错误
您需要注册一个恐慌钩子来std::panic::set_hook捕获输出。然后你可以用以下命令捕捉恐慌std::panic::catch_unwind:
use std::{
panic,
sync::{Arc, Mutex},
};
fn main() {
let global_buffer = Arc::new(Mutex::new(String::new()));
let old_hook = panic::take_hook();
panic::set_hook({
let global_buffer = global_buffer.clone();
Box::new(move |info| {
let mut global_buffer = global_buffer.lock().unwrap();
if let Some(s) = info.payload().downcast_ref::<&str>() {
global_buffer.push_str(s);
}
})
});
let result = panic::catch_unwind(|| {
panic!("test panic");
});
panic::set_hook(old_hook);
match result {
Ok(res) => res,
Err(_) => {
println!("caught panic!");
println!("I captured:\n\n{}", global_buffer.lock().unwrap())
}
}
}
Run Code Online (Sandbox Code Playgroud)
也可以看看:
Panics 消息当前写入 stderr,因此执行此操作的黑客方法是将 stderr 重定向到文件 ( cargo run 2>/path/to/panic.log)。
或者,您可以使用gag在程序本身中执行此操作(免责声明,我编写了这个库)。不幸的是,它不能在 Windows 上运行。
以下内容将重定向 stderr 直到stderr_redirect被删除:
use std::fs::OpenOptions;
use gag::Redirect;
let log = OpenOptions::new()
.truncate(true)
.read(true)
.create(true)
.write(true)
.open("/path/to/panic.log")
.unwrap();
let stderr_redirect = Redirect::stderr(log).unwrap();
// Your code here...
Run Code Online (Sandbox Code Playgroud)
您还可以通过执行以下操作将 stderr 缓冲到临时文件中:
use gag::BufferRedirect;
let mut stderr_buffer = BufferRedirect::stderr().unwrap();
Run Code Online (Sandbox Code Playgroud)