1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#![cfg_attr(feature = "nightly", deny(missing_docs))]
#![cfg_attr(feature = "nightly", feature(external_doc))]
#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
#[macro_use]
extern crate failure;
#[macro_use]
extern crate serde_derive;
extern crate termcolor;
mod report;
use report::{Method, Report};
use failure::Error as FailError;
use std::io::{Result as IoResult, Write};
use std::panic::PanicInfo;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
pub struct Metadata<'a> {
pub version: &'a str,
pub name: &'a str,
pub authors: &'a str,
pub homepage: &'a str,
}
#[macro_export]
macro_rules! setup_panic {
() => {
use human_panic::*;
use std::env;
use std::panic::{self, PanicInfo};
let meta = Metadata {
version: env!("CARGO_PKG_VERSION"),
name: env!("CARGO_PKG_NAME"),
authors: env!("CARGO_PKG_AUTHORS"),
homepage: env!("CARGO_PKG_HOMEPAGE"),
};
panic::set_hook(Box::new(move |info: &PanicInfo| {
let file_path =
handle_dump(info).expect("human-panic: dumping logs to disk failed");
print_msg(file_path, &meta)
.expect("human-panic: printing error message to console failed");
}));
};
}
pub fn print_msg(file_path: String, meta: &Metadata) -> IoResult<()> {
let (_version, name, authors, homepage) = (
meta.version,
meta.name,
meta.authors,
meta.homepage,
);
let stderr = BufferWriter::stderr(ColorChoice::Auto);
let mut buffer = stderr.buffer();
buffer.set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
writeln!(&mut buffer, "Well, this is embarrasing.\n")?;
writeln!(&mut buffer, "{} had a problem and crashed. To help us diagnose the problem you can send us a crash report.\n", name)?;
writeln!(&mut buffer, "We have generated a report file at \"{}\". Submit an issue or email with the subject of \"{} Crash Report\" and include the report as an attachment.\n", &file_path, name)?;
if !homepage.is_empty() {
writeln!(&mut buffer, "- Homepage: {}", homepage)?;
}
if !authors.is_empty() {
writeln!(&mut buffer, "- Authors: {}", authors)?;
}
writeln!(&mut buffer, "\nWe take privacy seriously, and do not perform any automated error collection. In order to improve the software, we rely on people to submit reports.\n")?;
writeln!(&mut buffer, "Thank you kindly!")?;
stderr.print(&buffer).unwrap();
Ok(())
}
pub fn handle_dump(panic_info: &PanicInfo) -> Result<String, FailError> {
let mut expl = String::new();
let payload = panic_info.payload().downcast_ref::<&str>();
if let Some(payload) = payload {
expl.push_str(&format!("Cause: {}. ", &payload));
}
match panic_info.location() {
Some(location) => expl.push_str(&format!(
"Panic occurred in file '{}' at line {}\n",
location.file(),
location.line()
)),
None => expl.push_str("Panic location uknown.\n"),
}
let report = Report::new(Method::Panic, expl);
return report.persist();
}