Save panics as structured data

This commit is contained in:
Joseph Lyons 2023-04-19 08:31:47 -04:00
parent c5e56a5e45
commit 27a6bacab8

View file

@ -21,7 +21,7 @@ use log::LevelFilter;
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use parking_lot::Mutex; use parking_lot::Mutex;
use project::Fs; use project::Fs;
use serde_json::json; use serde::{Deserialize, Serialize};
use settings::{ use settings::{
self, settings_file::SettingsFile, KeymapFileContent, Settings, SettingsFileContent, self, settings_file::SettingsFile, KeymapFileContent, Settings, SettingsFileContent,
WorkingDirectory, WorkingDirectory,
@ -317,6 +317,30 @@ fn init_logger() {
} }
} }
#[derive(Serialize, Deserialize)]
struct LocationData {
file: String,
line: u32,
}
#[derive(Serialize, Deserialize)]
struct Panic {
thread: String,
payload: String,
#[serde(skip_serializing_if = "Option::is_none")]
location_data: Option<LocationData>,
backtrace: Vec<String>,
// TODO
// stripped_backtrace: String,
}
#[derive(Serialize)]
struct PanicRequest {
panic: Panic,
version: String,
token: String,
}
fn init_panic_hook(app_version: String) { fn init_panic_hook(app_version: String) {
let is_pty = stdout_is_a_pty(); let is_pty = stdout_is_a_pty();
panic::set_hook(Box::new(move |info| { panic::set_hook(Box::new(move |info| {
@ -333,39 +357,38 @@ fn init_panic_hook(app_version: String) {
}, },
}; };
let message = match info.location() { let panic_data = Panic {
Some(location) => { thread: thread.into(),
format!( payload: payload.into(),
"thread '{}' panicked at '{}'\n{}:{}\n{:?}", location_data: info.location().map(|location| LocationData {
thread, file: location.file().into(),
payload, line: location.line(),
location.file(), }),
location.line(), backtrace: format!("{:?}", backtrace)
backtrace .split("\n")
) .map(|a| a.to_string())
} .collect(),
None => format!( // modified_backtrace: None,
"thread '{}' panicked at '{}'\n{:?}",
thread, payload, backtrace
),
}; };
if is_pty { if let Some(panic_data_json) = serde_json::to_string_pretty(&panic_data).log_err() {
eprintln!("{}", message); if is_pty {
return; eprintln!("{}", panic_data_json);
} return;
}
let timestamp = chrono::Utc::now().format("%Y_%m_%d %H_%M_%S").to_string(); let timestamp = chrono::Utc::now().format("%Y_%m_%d %H_%M_%S").to_string();
let panic_file_path = let panic_file_path =
paths::LOGS_DIR.join(format!("zed-{}-{}.panic", app_version, timestamp)); paths::LOGS_DIR.join(format!("zed-{}-{}.panic", app_version, timestamp));
let panic_file = std::fs::OpenOptions::new() let panic_file = std::fs::OpenOptions::new()
.append(true) .append(true)
.create(true) .create(true)
.open(&panic_file_path) .open(&panic_file_path)
.log_err(); .log_err();
if let Some(mut panic_file) = panic_file { if let Some(mut panic_file) = panic_file {
write!(&mut panic_file, "{}", message).log_err(); write!(&mut panic_file, "{}", panic_data_json).log_err();
panic_file.flush().log_err(); panic_file.flush().log_err();
}
} }
})); }));
} }
@ -402,15 +425,17 @@ fn upload_previous_panics(http: Arc<dyn HttpClient>, cx: &mut AppContext) {
}; };
if diagnostics_telemetry { if diagnostics_telemetry {
let text = smol::fs::read_to_string(&child_path) let panic_data_text = smol::fs::read_to_string(&child_path)
.await .await
.context("error reading panic file")?; .context("error reading panic file")?;
let body = serde_json::to_string(&json!({
"text": text, let body = serde_json::to_string(&PanicRequest {
"version": version, panic: serde_json::from_str(&panic_data_text)?,
"token": ZED_SECRET_CLIENT_TOKEN, version: version.to_string(),
})) token: ZED_SECRET_CLIENT_TOKEN.into(),
})
.unwrap(); .unwrap();
let request = Request::post(&panic_report_url) let request = Request::post(&panic_report_url)
.redirect_policy(isahc::config::RedirectPolicy::Follow) .redirect_policy(isahc::config::RedirectPolicy::Follow)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")