Remove legacy panic handling (#37947)

Julia Ryan and Conrad Irwin created

@maxdeviant We can eventually turn down the panic telemetry endpoint,
but should probably leave it up while there's still a bunch of stable
users hitting it.

@maxbrunsfeld We're optimistic that this change also fixed the macos
crashed-thread misreporting. We think it was because the
`CrashContext::exception` was getting set to `None` only on macos, while
on linux it was getting a real exception value from the sigtrap. Now
we've unified and it uses `SIGABRT` on both platforms (I need to double
check that this works as expected for windows).

We unconditionally set `RUST_BACKTRACE=1` for the current process so
that we see backtraces when running in a terminal by default. This
should be fine but I just wanted to note it since it's a bit abnormal.

Release Notes:

- N/A

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>

Change summary

Cargo.lock                       |  10 
Cargo.toml                       |   1 
crates/crashes/Cargo.toml        |   1 
crates/crashes/src/crashes.rs    |  43 ++
crates/proto/proto/app.proto     |   2 
crates/remote_server/Cargo.toml  |   3 
crates/remote_server/src/unix.rs | 119 +--------
crates/zed/Cargo.toml            |   2 
crates/zed/src/main.rs           |   9 
crates/zed/src/reliability.rs    | 423 +--------------------------------
10 files changed, 69 insertions(+), 544 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2853,9 +2853,9 @@ dependencies = [
 
 [[package]]
 name = "cfg-if"
-version = "1.0.0"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
 
 [[package]]
 name = "cfg_aliases"
@@ -4040,6 +4040,7 @@ name = "crashes"
 version = "0.1.0"
 dependencies = [
  "bincode",
+ "cfg-if",
  "crash-handler",
  "log",
  "mach2 0.5.0",
@@ -13502,9 +13503,7 @@ dependencies = [
  "askpass",
  "assistant_tool",
  "assistant_tools",
- "backtrace",
  "cargo_toml",
- "chrono",
  "clap",
  "client",
  "clock",
@@ -13549,7 +13548,6 @@ dependencies = [
  "shellexpand 2.1.2",
  "smol",
  "sysinfo",
- "telemetry_events",
  "thiserror 2.0.12",
  "toml 0.8.20",
  "unindent",
@@ -20512,7 +20510,6 @@ dependencies = [
  "breadcrumbs",
  "call",
  "channel",
- "chrono",
  "clap",
  "cli",
  "client",
@@ -20563,7 +20560,6 @@ dependencies = [
  "language_selector",
  "language_tools",
  "languages",
- "libc",
  "line_ending_selector",
  "log",
  "markdown",

Cargo.toml 🔗

@@ -472,6 +472,7 @@ blake3 = "1.5.3"
 bytes = "1.0"
 cargo_metadata = "0.19"
 cargo_toml = "0.21"
+cfg-if = "1.0.3"
 chrono = { version = "0.4", features = ["serde"] }
 ciborium = "0.2"
 circular-buffer = "1.0"

crates/crashes/Cargo.toml 🔗

@@ -7,6 +7,7 @@ license = "GPL-3.0-or-later"
 
 [dependencies]
 bincode.workspace = true
+cfg-if.workspace = true
 crash-handler.workspace = true
 log.workspace = true
 minidumper.workspace = true

crates/crashes/src/crashes.rs 🔗

@@ -1,4 +1,4 @@
-use crash_handler::CrashHandler;
+use crash_handler::{CrashEventResult, CrashHandler};
 use log::info;
 use minidumper::{Client, LoopAction, MinidumpBinary};
 use release_channel::{RELEASE_CHANNEL, ReleaseChannel};
@@ -10,7 +10,7 @@ use std::{
     env,
     fs::{self, File},
     io,
-    panic::Location,
+    panic::{self, PanicHookInfo},
     path::{Path, PathBuf},
     process::{self, Command},
     sync::{
@@ -33,7 +33,16 @@ static PANIC_THREAD_ID: AtomicU32 = AtomicU32::new(0);
 
 pub async fn init(crash_init: InitCrashHandler) {
     if *RELEASE_CHANNEL == ReleaseChannel::Dev && env::var("ZED_GENERATE_MINIDUMPS").is_err() {
+        let old_hook = panic::take_hook();
+        panic::set_hook(Box::new(move |info| {
+            unsafe { env::set_var("RUST_BACKTRACE", "1") };
+            old_hook(info);
+            // prevent the macOS crash dialog from popping up
+            std::process::exit(1);
+        }));
         return;
+    } else {
+        panic::set_hook(Box::new(panic_hook));
     }
 
     let exe = env::current_exe().expect("unable to find ourselves");
@@ -71,7 +80,7 @@ pub async fn init(crash_init: InitCrashHandler) {
         .unwrap();
 
     let client = Arc::new(client);
-    let handler = crash_handler::CrashHandler::attach(unsafe {
+    let handler = CrashHandler::attach(unsafe {
         let client = client.clone();
         crash_handler::make_crash_event(move |crash_context: &crash_handler::CrashContext| {
             // only request a minidump once
@@ -87,7 +96,7 @@ pub async fn init(crash_init: InitCrashHandler) {
             } else {
                 true
             };
-            crash_handler::CrashEventResult::Handled(res)
+            CrashEventResult::Handled(res)
         })
     })
     .expect("failed to attach signal handler");
@@ -257,8 +266,16 @@ impl minidumper::ServerHandler for CrashServer {
     }
 }
 
-pub fn handle_panic(message: String, span: Option<&Location>) {
-    let span = span
+pub fn panic_hook(info: &PanicHookInfo) {
+    let message = info
+        .payload()
+        .downcast_ref::<&str>()
+        .map(|s| s.to_string())
+        .or_else(|| info.payload().downcast_ref::<String>().cloned())
+        .unwrap_or_else(|| "Box<Any>".to_string());
+
+    let span = info
+        .location()
         .map(|loc| format!("{}:{}", loc.file(), loc.line()))
         .unwrap_or_default();
 
@@ -281,11 +298,15 @@ pub fn handle_panic(message: String, span: Option<&Location>) {
                 Ordering::SeqCst,
             );
 
-            #[cfg(target_os = "linux")]
-            CrashHandler.simulate_signal(crash_handler::Signal::Trap as u32);
-            #[cfg(not(target_os = "linux"))]
-            CrashHandler.simulate_exception(None);
-            break;
+            cfg_if::cfg_if! {
+                if #[cfg(target_os = "windows")] {
+                    // https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
+                    CrashHandler.simulate_exception(Some(234)); // (MORE_DATA_AVAILABLE)
+                    break;
+                } else {
+                    std::process::abort();
+                }
+            }
         }
         thread::sleep(retry_frequency);
     }

crates/proto/proto/app.proto 🔗

@@ -28,7 +28,7 @@ message GetCrashFiles {
 
 message GetCrashFilesResponse {
     repeated CrashReport crashes = 1;
-    repeated string legacy_panics = 2;
+    reserved 2; // old panics
 }
 
 message CrashReport {

crates/remote_server/Cargo.toml 🔗

@@ -24,8 +24,6 @@ test-support = ["fs/test-support"]
 [dependencies]
 anyhow.workspace = true
 askpass.workspace = true
-backtrace = "0.3"
-chrono.workspace = true
 clap.workspace = true
 client.workspace = true
 dap_adapters.workspace = true
@@ -61,7 +59,6 @@ settings.workspace = true
 shellexpand.workspace = true
 smol.workspace = true
 sysinfo.workspace = true
-telemetry_events.workspace = true
 util.workspace = true
 watch.workspace = true
 worktree.workspace = true

crates/remote_server/src/unix.rs 🔗

@@ -1,8 +1,8 @@
 use crate::HeadlessProject;
 use crate::headless_project::HeadlessAppState;
 use anyhow::{Context as _, Result, anyhow};
-use chrono::Utc;
-use client::{ProxySettings, telemetry};
+use client::ProxySettings;
+use util::ResultExt;
 
 use extension::ExtensionHostProxy;
 use fs::{Fs, RealFs};
@@ -29,26 +29,23 @@ use reqwest_client::ReqwestClient;
 use rpc::proto::{self, Envelope, REMOTE_SERVER_PROJECT_ID};
 use rpc::{AnyProtoClient, TypedEnvelope};
 use settings::{Settings, SettingsStore, watch_config_file};
+use smol::Async;
 use smol::channel::{Receiver, Sender};
 use smol::io::AsyncReadExt;
-
-use smol::Async;
 use smol::{net::unix::UnixListener, stream::StreamExt as _};
-use std::ffi::OsStr;
-use std::ops::ControlFlow;
-use std::process::ExitStatus;
-use std::str::FromStr;
-use std::sync::LazyLock;
-use std::{env, thread};
 use std::{
+    env,
+    ffi::OsStr,
+    fs::File,
     io::Write,
     mem,
+    ops::ControlFlow,
     path::{Path, PathBuf},
-    sync::Arc,
+    process::ExitStatus,
+    str::FromStr,
+    sync::{Arc, LazyLock},
 };
-use telemetry_events::LocationData;
 use thiserror::Error;
-use util::ResultExt;
 
 pub static VERSION: LazyLock<&str> = LazyLock::new(|| match *RELEASE_CHANNEL {
     ReleaseChannel::Stable | ReleaseChannel::Preview => env!("ZED_PKG_VERSION"),
@@ -71,12 +68,12 @@ fn init_logging_proxy() {
 
 fn init_logging_server(log_file_path: PathBuf) -> Result<Receiver<Vec<u8>>> {
     struct MultiWrite {
-        file: std::fs::File,
+        file: File,
         channel: Sender<Vec<u8>>,
         buffer: Vec<u8>,
     }
 
-    impl std::io::Write for MultiWrite {
+    impl Write for MultiWrite {
         fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
             let written = self.file.write(buf)?;
             self.buffer.extend_from_slice(&buf[..written]);
@@ -120,87 +117,6 @@ fn init_logging_server(log_file_path: PathBuf) -> Result<Receiver<Vec<u8>>> {
     Ok(rx)
 }
 
-fn init_panic_hook(session_id: String) {
-    std::panic::set_hook(Box::new(move |info| {
-        let payload = info
-            .payload()
-            .downcast_ref::<&str>()
-            .map(|s| s.to_string())
-            .or_else(|| info.payload().downcast_ref::<String>().cloned())
-            .unwrap_or_else(|| "Box<Any>".to_string());
-
-        crashes::handle_panic(payload.clone(), info.location());
-
-        let backtrace = backtrace::Backtrace::new();
-        let mut backtrace = backtrace
-            .frames()
-            .iter()
-            .flat_map(|frame| {
-                frame
-                    .symbols()
-                    .iter()
-                    .filter_map(|frame| Some(format!("{:#}", frame.name()?)))
-            })
-            .collect::<Vec<_>>();
-
-        // Strip out leading stack frames for rust panic-handling.
-        if let Some(ix) = backtrace
-            .iter()
-            .position(|name| name == "rust_begin_unwind")
-        {
-            backtrace.drain(0..=ix);
-        }
-
-        let thread = thread::current();
-        let thread_name = thread.name().unwrap_or("<unnamed>");
-
-        log::error!(
-            "panic occurred: {}\nBacktrace:\n{}",
-            &payload,
-            backtrace.join("\n")
-        );
-
-        let panic_data = telemetry_events::Panic {
-            thread: thread_name.into(),
-            payload,
-            location_data: info.location().map(|location| LocationData {
-                file: location.file().into(),
-                line: location.line(),
-            }),
-            app_version: format!("remote-server-{}", *VERSION),
-            app_commit_sha: option_env!("ZED_COMMIT_SHA").map(|sha| sha.into()),
-            release_channel: RELEASE_CHANNEL.dev_name().into(),
-            target: env!("TARGET").to_owned().into(),
-            os_name: telemetry::os_name(),
-            os_version: Some(telemetry::os_version()),
-            architecture: env::consts::ARCH.into(),
-            panicked_on: Utc::now().timestamp_millis(),
-            backtrace,
-            system_id: None,       // Set on SSH client
-            installation_id: None, // Set on SSH client
-
-            // used on this end to associate panics with minidumps, but will be replaced on the SSH client
-            session_id: session_id.clone(),
-        };
-
-        if let Some(panic_data_json) = serde_json::to_string(&panic_data).log_err() {
-            let timestamp = chrono::Utc::now().format("%Y_%m_%d %H_%M_%S").to_string();
-            let panic_file_path = paths::logs_dir().join(format!("zed-{timestamp}.panic"));
-            let panic_file = std::fs::OpenOptions::new()
-                .append(true)
-                .create(true)
-                .open(&panic_file_path)
-                .log_err();
-            if let Some(mut panic_file) = panic_file {
-                writeln!(&mut panic_file, "{panic_data_json}").log_err();
-                panic_file.flush().log_err();
-            }
-        }
-
-        std::process::abort();
-    }));
-}
-
 fn handle_crash_files_requests(project: &Entity<HeadlessProject>, client: &AnyProtoClient) {
     client.add_request_handler(
         project.downgrade(),
@@ -249,10 +165,7 @@ fn handle_crash_files_requests(project: &Entity<HeadlessProject>, client: &AnyPr
                 }
             }
 
-            anyhow::Ok(proto::GetCrashFilesResponse {
-                crashes,
-                legacy_panics,
-            })
+            anyhow::Ok(proto::GetCrashFilesResponse { crashes })
         },
     );
 }
@@ -434,13 +347,12 @@ pub fn execute_run(
     let id = std::process::id().to_string();
     app.background_executor()
         .spawn(crashes::init(crashes::InitCrashHandler {
-            session_id: id.clone(),
+            session_id: id,
             zed_version: VERSION.to_owned(),
             release_channel: release_channel::RELEASE_CHANNEL_NAME.clone(),
             commit_sha: option_env!("ZED_COMMIT_SHA").unwrap_or("no_sha").to_owned(),
         }))
         .detach();
-    init_panic_hook(id);
     let log_rx = init_logging_server(log_file)?;
     log::info!(
         "starting up. pid_file: {:?}, stdin_socket: {:?}, stdout_socket: {:?}, stderr_socket: {:?}",
@@ -627,13 +539,12 @@ pub(crate) fn execute_proxy(
 
     let id = std::process::id().to_string();
     smol::spawn(crashes::init(crashes::InitCrashHandler {
-        session_id: id.clone(),
+        session_id: id,
         zed_version: VERSION.to_owned(),
         release_channel: release_channel::RELEASE_CHANNEL_NAME.clone(),
         commit_sha: option_env!("ZED_COMMIT_SHA").unwrap_or("no_sha").to_owned(),
     }))
     .detach();
-    init_panic_hook(id);
 
     log::info!("starting proxy process. PID: {}", std::process::id());
 

crates/zed/Cargo.toml 🔗

@@ -37,7 +37,6 @@ bincode.workspace = true
 breadcrumbs.workspace = true
 call.workspace = true
 channel.workspace = true
-chrono.workspace = true
 clap.workspace = true
 cli.workspace = true
 client.workspace = true
@@ -93,7 +92,6 @@ language_selector.workspace = true
 language_tools.workspace = true
 languages = { workspace = true, features = ["load-grammars"] }
 line_ending_selector.workspace = true
-libc.workspace = true
 log.workspace = true
 markdown.workspace = true
 markdown_preview.workspace = true

crates/zed/src/main.rs 🔗

@@ -278,13 +278,6 @@ pub fn main() {
                 .unwrap_or_else(|| "no sha".to_owned()),
         }))
         .detach();
-    reliability::init_panic_hook(
-        app_version,
-        app_commit_sha.clone(),
-        system_id.as_ref().map(|id| id.to_string()),
-        installation_id.as_ref().map(|id| id.to_string()),
-        session_id.clone(),
-    );
 
     let (open_listener, mut open_rx) = OpenListener::new();
 
@@ -542,8 +535,6 @@ pub fn main() {
         reliability::init(
             client.http_client(),
             system_id.as_ref().map(|id| id.to_string()),
-            installation_id.clone().map(|id| id.to_string()),
-            session_id.clone(),
             cx,
         );
 

crates/zed/src/reliability.rs 🔗

@@ -1,226 +1,32 @@
-use crate::stdout_is_a_pty;
 use anyhow::{Context as _, Result};
-use backtrace::{self, Backtrace};
-use chrono::Utc;
-use client::{
-    TelemetrySettings,
-    telemetry::{self, MINIDUMP_ENDPOINT},
-};
-use db::kvp::KEY_VALUE_STORE;
+use client::{TelemetrySettings, telemetry::MINIDUMP_ENDPOINT};
 use futures::AsyncReadExt;
-use gpui::{App, AppContext as _, SemanticVersion};
-use http_client::{self, HttpClient, HttpClientWithUrl, HttpRequestExt, Method};
-use paths::{crashes_dir, crashes_retired_dir};
+use gpui::{App, AppContext as _};
+use http_client::{self, HttpClient, HttpClientWithUrl};
 use project::Project;
 use proto::{CrashReport, GetCrashFilesResponse};
-use release_channel::{AppCommitSha, RELEASE_CHANNEL, ReleaseChannel};
 use reqwest::multipart::{Form, Part};
 use settings::Settings;
 use smol::stream::StreamExt;
-use std::{
-    env,
-    ffi::{OsStr, c_void},
-    fs,
-    io::Write,
-    panic,
-    sync::{
-        Arc,
-        atomic::{AtomicU32, Ordering},
-    },
-    thread,
-};
-use telemetry_events::{LocationData, Panic, PanicRequest};
-use url::Url;
+use std::{ffi::OsStr, fs, sync::Arc};
 use util::ResultExt;
 
-static PANIC_COUNT: AtomicU32 = AtomicU32::new(0);
-
-pub fn init_panic_hook(
-    app_version: SemanticVersion,
-    app_commit_sha: Option<AppCommitSha>,
-    system_id: Option<String>,
-    installation_id: Option<String>,
-    session_id: String,
-) {
-    let is_pty = stdout_is_a_pty();
-
-    panic::set_hook(Box::new(move |info| {
-        let prior_panic_count = PANIC_COUNT.fetch_add(1, Ordering::SeqCst);
-        if prior_panic_count > 0 {
-            // Give the panic-ing thread time to write the panic file
-            loop {
-                thread::yield_now();
-            }
-        }
-
-        let payload = info
-            .payload()
-            .downcast_ref::<&str>()
-            .map(|s| s.to_string())
-            .or_else(|| info.payload().downcast_ref::<String>().cloned())
-            .unwrap_or_else(|| "Box<Any>".to_string());
-
-        if *release_channel::RELEASE_CHANNEL != ReleaseChannel::Dev
-            || env::var("ZED_GENERATE_MINIDUMPS").is_ok()
-        {
-            crashes::handle_panic(payload.clone(), info.location());
-        }
-
-        let thread = thread::current();
-        let thread_name = thread.name().unwrap_or("<unnamed>");
-
-        if *release_channel::RELEASE_CHANNEL == ReleaseChannel::Dev {
-            let location = info.location().unwrap();
-            let backtrace = Backtrace::new();
-            eprintln!(
-                "Thread {:?} panicked with {:?} at {}:{}:{}\n{}{:?}",
-                thread_name,
-                payload,
-                location.file(),
-                location.line(),
-                location.column(),
-                match app_commit_sha.as_ref() {
-                    Some(commit_sha) => format!(
-                        "https://github.com/zed-industries/zed/blob/{}/{}#L{} \
-                        (may not be uploaded, line may be incorrect if files modified)\n",
-                        commit_sha.full(),
-                        location.file(),
-                        location.line()
-                    ),
-                    None => "".to_string(),
-                },
-                backtrace,
-            );
-            if MINIDUMP_ENDPOINT.is_none() {
-                std::process::exit(-1);
-            }
-        }
-        let main_module_base_address = get_main_module_base_address();
-
-        let backtrace = Backtrace::new();
-        let mut symbols = backtrace
-            .frames()
-            .iter()
-            .flat_map(|frame| {
-                let base = frame
-                    .module_base_address()
-                    .unwrap_or(main_module_base_address);
-                frame.symbols().iter().map(move |symbol| {
-                    format!(
-                        "{}+{}",
-                        symbol
-                            .name()
-                            .as_ref()
-                            .map_or("<unknown>".to_owned(), <_>::to_string),
-                        (frame.ip() as isize).saturating_sub(base as isize)
-                    )
-                })
-            })
-            .collect::<Vec<_>>();
-
-        // Strip out leading stack frames for rust panic-handling.
-        if let Some(ix) = symbols
-            .iter()
-            .position(|name| name == "rust_begin_unwind" || name == "_rust_begin_unwind")
-        {
-            symbols.drain(0..=ix);
-        }
-
-        let panic_data = telemetry_events::Panic {
-            thread: thread_name.into(),
-            payload,
-            location_data: info.location().map(|location| LocationData {
-                file: location.file().into(),
-                line: location.line(),
-            }),
-            app_version: app_version.to_string(),
-            app_commit_sha: app_commit_sha.as_ref().map(|sha| sha.full()),
-            release_channel: RELEASE_CHANNEL.dev_name().into(),
-            target: env!("TARGET").to_owned().into(),
-            os_name: telemetry::os_name(),
-            os_version: Some(telemetry::os_version()),
-            architecture: env::consts::ARCH.into(),
-            panicked_on: Utc::now().timestamp_millis(),
-            backtrace: symbols,
-            system_id: system_id.clone(),
-            installation_id: installation_id.clone(),
-            session_id: session_id.clone(),
-        };
-
-        if let Some(panic_data_json) = serde_json::to_string_pretty(&panic_data).log_err() {
-            log::error!("{}", panic_data_json);
-        }
-        zlog::flush();
-
-        if (!is_pty || MINIDUMP_ENDPOINT.is_some())
-            && let Some(panic_data_json) = serde_json::to_string(&panic_data).log_err()
-        {
-            let timestamp = chrono::Utc::now().format("%Y_%m_%d %H_%M_%S").to_string();
-            let panic_file_path = paths::logs_dir().join(format!("zed-{timestamp}.panic"));
-            let panic_file = fs::OpenOptions::new()
-                .write(true)
-                .create_new(true)
-                .open(&panic_file_path)
-                .log_err();
-            if let Some(mut panic_file) = panic_file {
-                writeln!(&mut panic_file, "{panic_data_json}").log_err();
-                panic_file.flush().log_err();
-            }
-        }
-
-        std::process::abort();
-    }));
-}
-
-#[cfg(not(target_os = "windows"))]
-fn get_main_module_base_address() -> *mut c_void {
-    let mut dl_info = libc::Dl_info {
-        dli_fname: std::ptr::null(),
-        dli_fbase: std::ptr::null_mut(),
-        dli_sname: std::ptr::null(),
-        dli_saddr: std::ptr::null_mut(),
-    };
-    unsafe {
-        libc::dladdr(get_main_module_base_address as _, &mut dl_info);
-    }
-    dl_info.dli_fbase
-}
-
-#[cfg(target_os = "windows")]
-fn get_main_module_base_address() -> *mut c_void {
-    std::ptr::null_mut()
-}
-
-pub fn init(
-    http_client: Arc<HttpClientWithUrl>,
-    system_id: Option<String>,
-    installation_id: Option<String>,
-    session_id: String,
-    cx: &mut App,
-) {
+pub fn init(http_client: Arc<HttpClientWithUrl>, installation_id: Option<String>, cx: &mut App) {
     #[cfg(target_os = "macos")]
     monitor_main_thread_hangs(http_client.clone(), installation_id.clone(), cx);
 
-    let Some(panic_report_url) = http_client
-        .build_zed_api_url("/telemetry/panics", &[])
-        .log_err()
-    else {
-        return;
-    };
-
-    upload_panics_and_crashes(
-        http_client.clone(),
-        panic_report_url.clone(),
-        installation_id.clone(),
-        cx,
-    );
+    if client::TelemetrySettings::get_global(cx).diagnostics {
+        let client = http_client.clone();
+        let id = installation_id.clone();
+        cx.background_spawn(async move {
+            upload_previous_minidumps(client, id).await.warn_on_err();
+        })
+        .detach()
+    }
 
     cx.observe_new(move |project: &mut Project, _, cx| {
         let http_client = http_client.clone();
-        let panic_report_url = panic_report_url.clone();
-        let session_id = session_id.clone();
         let installation_id = installation_id.clone();
-        let system_id = system_id.clone();
 
         let Some(remote_client) = project.remote_client() else {
             return;
@@ -231,19 +37,7 @@ pub fn init(
             }
             let request = client.proto_client().request(proto::GetCrashFiles {});
             cx.background_spawn(async move {
-                let GetCrashFilesResponse {
-                    legacy_panics,
-                    crashes,
-                } = request.await?;
-
-                for panic in legacy_panics {
-                    if let Some(mut panic) = serde_json::from_str::<Panic>(&panic).log_err() {
-                        panic.session_id = session_id.clone();
-                        panic.system_id = system_id.clone();
-                        panic.installation_id = installation_id.clone();
-                        upload_panic(&http_client, &panic_report_url, panic, &mut None).await?;
-                    }
-                }
+                let GetCrashFilesResponse { crashes } = request.await?;
 
                 let Some(endpoint) = MINIDUMP_ENDPOINT.as_ref() else {
                     return Ok(());
@@ -297,6 +91,7 @@ pub fn monitor_main_thread_hangs(
     use parking_lot::Mutex;
 
     use http_client::Method;
+    use release_channel::ReleaseChannel;
     use std::{
         ffi::c_int,
         sync::{OnceLock, mpsc},
@@ -440,7 +235,7 @@ pub fn monitor_main_thread_hangs(
                         app_version: Some(app_version),
                         os_name: os_name.clone(),
                         os_version: Some(os_version.clone()),
-                        architecture: env::consts::ARCH.into(),
+                        architecture: std::env::consts::ARCH.into(),
                         installation_id: installation_id.clone(),
                     };
 
@@ -477,86 +272,6 @@ pub fn monitor_main_thread_hangs(
         .detach()
 }
 
-fn upload_panics_and_crashes(
-    http: Arc<HttpClientWithUrl>,
-    panic_report_url: Url,
-    installation_id: Option<String>,
-    cx: &App,
-) {
-    if !client::TelemetrySettings::get_global(cx).diagnostics {
-        return;
-    }
-    cx.background_spawn(async move {
-        upload_previous_minidumps(http.clone(), installation_id.clone())
-            .await
-            .warn_on_err();
-        let most_recent_panic = upload_previous_panics(http.clone(), &panic_report_url)
-            .await
-            .log_err()
-            .flatten();
-        upload_previous_crashes(http, most_recent_panic, installation_id)
-            .await
-            .log_err();
-    })
-    .detach()
-}
-
-/// Uploads panics via `zed.dev`.
-async fn upload_previous_panics(
-    http: Arc<HttpClientWithUrl>,
-    panic_report_url: &Url,
-) -> anyhow::Result<Option<(i64, String)>> {
-    let mut children = smol::fs::read_dir(paths::logs_dir()).await?;
-
-    let mut most_recent_panic = None;
-
-    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;
-        };
-
-        if !filename.starts_with("zed") {
-            continue;
-        }
-
-        let panic_file_content = smol::fs::read_to_string(&child_path)
-            .await
-            .context("error reading panic file")?;
-
-        let panic: Option<Panic> = serde_json::from_str(&panic_file_content)
-            .log_err()
-            .or_else(|| {
-                panic_file_content
-                    .lines()
-                    .next()
-                    .and_then(|line| serde_json::from_str(line).ok())
-            })
-            .unwrap_or_else(|| {
-                log::error!("failed to deserialize panic file {:?}", panic_file_content);
-                None
-            });
-
-        if let Some(panic) = panic
-            && upload_panic(&http, panic_report_url, panic, &mut most_recent_panic).await?
-        {
-            // We've done what we can, delete the file
-            fs::remove_file(child_path)
-                .context("error removing panic")
-                .log_err();
-        }
-    }
-
-    Ok(most_recent_panic)
-}
-
 pub async fn upload_previous_minidumps(
     http: Arc<HttpClientWithUrl>,
     installation_id: Option<String>,
@@ -728,109 +443,3 @@ impl FormExt for Form {
         }
     }
 }
-
-async fn upload_panic(
-    http: &Arc<HttpClientWithUrl>,
-    panic_report_url: &Url,
-    panic: telemetry_events::Panic,
-    most_recent_panic: &mut Option<(i64, String)>,
-) -> Result<bool> {
-    *most_recent_panic = Some((panic.panicked_on, panic.payload.clone()));
-
-    let json_bytes = serde_json::to_vec(&PanicRequest { panic }).unwrap();
-
-    let Some(checksum) = client::telemetry::calculate_json_checksum(&json_bytes) else {
-        return Ok(false);
-    };
-
-    let Ok(request) = http_client::Request::builder()
-        .method(Method::POST)
-        .uri(panic_report_url.as_ref())
-        .header("x-zed-checksum", checksum)
-        .body(json_bytes.into())
-    else {
-        return Ok(false);
-    };
-
-    let response = http.send(request).await.context("error sending panic")?;
-    if !response.status().is_success() {
-        log::error!("Error uploading panic to server: {}", response.status());
-    }
-
-    Ok(true)
-}
-const LAST_CRASH_UPLOADED: &str = "LAST_CRASH_UPLOADED";
-
-/// upload crashes from apple's diagnostic reports to our server.
-/// (only if telemetry is enabled)
-async fn upload_previous_crashes(
-    http: Arc<HttpClientWithUrl>,
-    most_recent_panic: Option<(i64, String)>,
-    installation_id: Option<String>,
-) -> Result<()> {
-    let last_uploaded = KEY_VALUE_STORE
-        .read_kvp(LAST_CRASH_UPLOADED)?
-        .unwrap_or("zed-2024-01-17-221900.ips".to_string()); // don't upload old crash reports from before we had this.
-    let mut uploaded = last_uploaded.clone();
-
-    let crash_report_url = http.build_zed_api_url("/telemetry/crashes", &[])?;
-
-    // Crash directories are only set on macOS.
-    for dir in [crashes_dir(), crashes_retired_dir()]
-        .iter()
-        .filter_map(|d| d.as_deref())
-    {
-        let mut children = smol::fs::read_dir(&dir).await?;
-        while let Some(child) = children.next().await {
-            let child = child?;
-            let Some(filename) = child
-                .path()
-                .file_name()
-                .map(|f| f.to_string_lossy().to_lowercase())
-            else {
-                continue;
-            };
-
-            if !filename.starts_with("zed-") || !filename.ends_with(".ips") {
-                continue;
-            }
-
-            if filename <= last_uploaded {
-                continue;
-            }
-
-            let body = smol::fs::read_to_string(&child.path())
-                .await
-                .context("error reading crash file")?;
-
-            let mut request = http_client::Request::post(&crash_report_url.to_string())
-                .follow_redirects(http_client::RedirectPolicy::FollowAll)
-                .header("Content-Type", "text/plain");
-
-            if let Some((panicked_on, payload)) = most_recent_panic.as_ref() {
-                request = request
-                    .header("x-zed-panicked-on", format!("{panicked_on}"))
-                    .header("x-zed-panic", payload)
-            }
-            if let Some(installation_id) = installation_id.as_ref() {
-                request = request.header("x-zed-installation-id", installation_id);
-            }
-
-            let request = request.body(body.into())?;
-
-            let response = http.send(request).await.context("error sending crash")?;
-            if !response.status().is_success() {
-                log::error!("Error uploading crash to server: {}", response.status());
-            }
-
-            if uploaded < filename {
-                uploaded.clone_from(&filename);
-                KEY_VALUE_STORE
-                    .write_kvp(LAST_CRASH_UPLOADED.to_string(), filename)
-                    .await?;
-            }
-        }
-    }
-
-    Ok(())
-}