mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-11 13:10:54 +00:00
Add the ability to opt-out of panic reporting
Co-authored-by: Kay <kay@zed.dev>
This commit is contained in:
parent
a222821dfa
commit
866f0e1344
3 changed files with 119 additions and 72 deletions
|
@ -79,6 +79,13 @@
|
|||
"hard_tabs": false,
|
||||
// How many columns a tab should occupy.
|
||||
"tab_size": 4,
|
||||
// Control what info Zed sends to our servers
|
||||
"telemetry": {
|
||||
// Send debug info like crash reports.
|
||||
"diagnostics": true,
|
||||
// Send anonymized usage data like what languages you're using Zed with.
|
||||
"metrics": true
|
||||
},
|
||||
// Git gutter behavior configuration.
|
||||
"git": {
|
||||
// Control whether the git gutter is shown. May take 2 values:
|
||||
|
|
|
@ -51,9 +51,17 @@ pub struct Settings {
|
|||
pub language_overrides: HashMap<Arc<str>, EditorSettings>,
|
||||
pub lsp: HashMap<Arc<str>, LspSettings>,
|
||||
pub theme: Arc<Theme>,
|
||||
pub telemetry_defaults: TelemetrySettings,
|
||||
pub telemetry_overrides: TelemetrySettings,
|
||||
pub staff_mode: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct TelemetrySettings {
|
||||
diagnostics: Option<bool>,
|
||||
metrics: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct FeatureFlags {
|
||||
pub experimental_themes: bool,
|
||||
|
@ -302,6 +310,8 @@ pub struct SettingsFileContent {
|
|||
#[serde(default)]
|
||||
pub theme: Option<String>,
|
||||
#[serde(default)]
|
||||
pub telemetry: TelemetrySettings,
|
||||
#[serde(default)]
|
||||
pub staff_mode: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -312,6 +322,7 @@ pub struct LspSettings {
|
|||
}
|
||||
|
||||
impl Settings {
|
||||
/// Fill out the settings corresponding to the default.json file, overrides will be set later
|
||||
pub fn defaults(
|
||||
assets: impl AssetSource,
|
||||
font_cache: &FontCache,
|
||||
|
@ -363,11 +374,13 @@ impl Settings {
|
|||
language_overrides: Default::default(),
|
||||
lsp: defaults.lsp.clone(),
|
||||
theme: themes.get(&defaults.theme.unwrap()).unwrap(),
|
||||
|
||||
telemetry_defaults: defaults.telemetry,
|
||||
telemetry_overrides: Default::default(),
|
||||
staff_mode: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Fill out the overrride and etc. settings from the user's settings.json
|
||||
pub fn set_user_settings(
|
||||
&mut self,
|
||||
data: SettingsFileContent,
|
||||
|
@ -419,6 +432,7 @@ impl Settings {
|
|||
self.terminal_overrides.copy_on_select = data.terminal.copy_on_select;
|
||||
self.terminal_overrides = data.terminal;
|
||||
self.language_overrides = data.languages;
|
||||
self.telemetry_overrides = data.telemetry;
|
||||
self.lsp = data.lsp;
|
||||
}
|
||||
|
||||
|
@ -489,6 +503,20 @@ impl Settings {
|
|||
.unwrap_or_else(|| R::default())
|
||||
}
|
||||
|
||||
pub fn telemetry_diagnostics(&self) -> bool {
|
||||
self.telemetry_overrides
|
||||
.diagnostics
|
||||
.or(self.telemetry_defaults.diagnostics)
|
||||
.expect("missing default")
|
||||
}
|
||||
|
||||
pub fn telemetry_metrics(&self) -> bool {
|
||||
self.telemetry_overrides
|
||||
.metrics
|
||||
.or(self.telemetry_defaults.metrics)
|
||||
.expect("missing default")
|
||||
}
|
||||
|
||||
pub fn terminal_scroll(&self) -> AlternateScroll {
|
||||
self.terminal_setting(|terminal_setting| terminal_setting.alternate_scroll.as_ref())
|
||||
}
|
||||
|
@ -540,6 +568,8 @@ impl Settings {
|
|||
lsp: Default::default(),
|
||||
projects_online_by_default: true,
|
||||
theme: gpui::fonts::with_font_cache(cx.font_cache().clone(), Default::default),
|
||||
telemetry_defaults: Default::default(),
|
||||
telemetry_overrides: Default::default(),
|
||||
staff_mode: false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ use futures::{
|
|||
channel::{mpsc, oneshot},
|
||||
FutureExt, SinkExt, StreamExt,
|
||||
};
|
||||
use gpui::{executor::Background, App, AssetSource, AsyncAppContext, Task, ViewContext};
|
||||
use gpui::{App, AssetSource, AsyncAppContext, MutableAppContext, Task, ViewContext};
|
||||
use isahc::{config::Configurable, Request};
|
||||
use language::LanguageRegistry;
|
||||
use log::LevelFilter;
|
||||
|
@ -50,10 +50,13 @@ fn main() {
|
|||
|
||||
log::info!("========== starting zed ==========");
|
||||
let mut app = gpui::App::new(Assets).unwrap();
|
||||
|
||||
let app_version = ZED_APP_VERSION
|
||||
.or_else(|| app.platform().app_version().ok())
|
||||
.map_or("dev".to_string(), |v| v.to_string());
|
||||
init_panic_hook(app_version, http.clone(), app.background());
|
||||
init_panic_hook(app_version);
|
||||
|
||||
app.background();
|
||||
|
||||
load_embedded_fonts(&app);
|
||||
|
||||
|
@ -61,7 +64,6 @@ fn main() {
|
|||
|
||||
let themes = ThemeRegistry::new(Assets, app.font_cache());
|
||||
let default_settings = Settings::defaults(Assets, &app.font_cache(), &themes);
|
||||
|
||||
let config_files = load_config_files(&app, fs.clone());
|
||||
|
||||
let login_shell_env_loaded = if stdout_is_a_pty() {
|
||||
|
@ -88,6 +90,18 @@ fn main() {
|
|||
cx.set_global(*RELEASE_CHANNEL);
|
||||
cx.set_global(HomeDir(paths::HOME.to_path_buf()));
|
||||
|
||||
let (settings_file_content, keymap_file) = cx.background().block(config_files).unwrap();
|
||||
|
||||
//Setup settings global before binding actions
|
||||
cx.set_global(SettingsFile::new(
|
||||
&paths::SETTINGS,
|
||||
settings_file_content.clone(),
|
||||
fs.clone(),
|
||||
));
|
||||
|
||||
watch_settings_file(default_settings, settings_file_content, themes.clone(), cx);
|
||||
upload_previous_panics(http.clone(), cx);
|
||||
|
||||
let client = client::Client::new(http.clone(), cx);
|
||||
let mut languages = LanguageRegistry::new(login_shell_env_loaded);
|
||||
languages.set_language_server_download_dir(paths::LANGUAGES_DIR.clone());
|
||||
|
@ -97,15 +111,6 @@ fn main() {
|
|||
.spawn(languages::init(languages.clone(), cx.background().clone()));
|
||||
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx));
|
||||
|
||||
let (settings_file_content, keymap_file) = cx.background().block(config_files).unwrap();
|
||||
|
||||
//Setup settings global before binding actions
|
||||
cx.set_global(SettingsFile::new(
|
||||
&paths::SETTINGS,
|
||||
settings_file_content.clone(),
|
||||
fs.clone(),
|
||||
));
|
||||
watch_settings_file(default_settings, settings_file_content, themes.clone(), cx);
|
||||
watch_keymap_file(keymap_file, cx);
|
||||
|
||||
context_menu::init(cx);
|
||||
|
@ -251,65 +256,7 @@ fn init_logger() {
|
|||
}
|
||||
}
|
||||
|
||||
fn init_panic_hook(app_version: String, http: Arc<dyn HttpClient>, background: Arc<Background>) {
|
||||
background
|
||||
.spawn({
|
||||
async move {
|
||||
let panic_report_url = format!("{}/api/panic", &*client::ZED_SERVER_URL);
|
||||
let mut children = smol::fs::read_dir(&*paths::LOGS_DIR).await?;
|
||||
while let Some(child) = children.next().await {
|
||||
let child = child?;
|
||||
let child_path = child.path();
|
||||
if child_path.extension() != Some(OsStr::new("panic")) {
|
||||
continue;
|
||||
}
|
||||
let filename = if let Some(filename) = child_path.file_name() {
|
||||
filename.to_string_lossy()
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut components = filename.split('-');
|
||||
if components.next() != Some("zed") {
|
||||
continue;
|
||||
}
|
||||
let version = if let Some(version) = components.next() {
|
||||
version
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let text = smol::fs::read_to_string(&child_path)
|
||||
.await
|
||||
.context("error reading panic file")?;
|
||||
let body = serde_json::to_string(&json!({
|
||||
"text": text,
|
||||
"version": version,
|
||||
"token": ZED_SECRET_CLIENT_TOKEN,
|
||||
}))
|
||||
.unwrap();
|
||||
let request = Request::post(&panic_report_url)
|
||||
.redirect_policy(isahc::config::RedirectPolicy::Follow)
|
||||
.header("Content-Type", "application/json")
|
||||
.body(body.into())?;
|
||||
let response = http.send(request).await.context("error sending panic")?;
|
||||
if response.status().is_success() {
|
||||
std::fs::remove_file(child_path)
|
||||
.context("error removing panic after sending it successfully")
|
||||
.log_err();
|
||||
} else {
|
||||
return Err(anyhow!(
|
||||
"error uploading panic to server: {}",
|
||||
response.status()
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok::<_, anyhow::Error>(())
|
||||
}
|
||||
.log_err()
|
||||
})
|
||||
.detach();
|
||||
|
||||
fn init_panic_hook(app_version: String) {
|
||||
let is_pty = stdout_is_a_pty();
|
||||
panic::set_hook(Box::new(move |info| {
|
||||
let backtrace = Backtrace::new();
|
||||
|
@ -358,6 +305,69 @@ fn init_panic_hook(app_version: String, http: Arc<dyn HttpClient>, background: A
|
|||
}));
|
||||
}
|
||||
|
||||
fn upload_previous_panics(http: Arc<dyn HttpClient>, cx: &mut MutableAppContext) {
|
||||
let diagnostics_telemetry = cx.global::<Settings>().telemetry_diagnostics();
|
||||
|
||||
cx.background()
|
||||
.spawn({
|
||||
async move {
|
||||
let panic_report_url = format!("{}/api/panic", &*client::ZED_SERVER_URL);
|
||||
let mut children = smol::fs::read_dir(&*paths::LOGS_DIR).await?;
|
||||
while let Some(child) = children.next().await {
|
||||
let child = child?;
|
||||
let child_path = child.path();
|
||||
|
||||
if child_path.extension() != Some(OsStr::new("panic")) {
|
||||
continue;
|
||||
}
|
||||
let filename = if let Some(filename) = child_path.file_name() {
|
||||
filename.to_string_lossy()
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut components = filename.split('-');
|
||||
if components.next() != Some("zed") {
|
||||
continue;
|
||||
}
|
||||
let version = if let Some(version) = components.next() {
|
||||
version
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if diagnostics_telemetry {
|
||||
let text = smol::fs::read_to_string(&child_path)
|
||||
.await
|
||||
.context("error reading panic file")?;
|
||||
let body = serde_json::to_string(&json!({
|
||||
"text": text,
|
||||
"version": version,
|
||||
"token": ZED_SECRET_CLIENT_TOKEN,
|
||||
}))
|
||||
.unwrap();
|
||||
let request = Request::post(&panic_report_url)
|
||||
.redirect_policy(isahc::config::RedirectPolicy::Follow)
|
||||
.header("Content-Type", "application/json")
|
||||
.body(body.into())?;
|
||||
let response = http.send(request).await.context("error sending panic")?;
|
||||
if !response.status().is_success() {
|
||||
log::error!("Error uploading panic to server: {}", response.status());
|
||||
}
|
||||
}
|
||||
|
||||
// We've done what we can, delete the file
|
||||
std::fs::remove_file(child_path)
|
||||
.context("error removing panic")
|
||||
.log_err();
|
||||
}
|
||||
Ok::<_, anyhow::Error>(())
|
||||
}
|
||||
.log_err()
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
async fn load_login_shell_environment() -> Result<()> {
|
||||
let marker = "ZED_LOGIN_SHELL_START";
|
||||
let shell = env::var("SHELL").context(
|
||||
|
|
Loading…
Reference in a new issue