Add minidump crash reporting (#35263)
- [x] Handle uploading minidumps from the remote_server - [x] Associate minidumps with panics with some sort of ID (we don't use session_id on the remote) - [x] Update the protobufs and client/server code to request panics - [x] Upload minidumps with no corresponding panic - [x] Fill in panic info when there _is_ a corresponding panic - [x] Use an env var for the sentry endpoint instead of hardcoding it Release Notes: - Zed now generates minidumps for crash reporting --------- Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
07e3d53d58
commit
669c57b45f
25 changed files with 709 additions and 135 deletions
|
@ -24,6 +24,7 @@ http.workspace = true
|
|||
http-body.workspace = true
|
||||
log.workspace = true
|
||||
parking_lot.workspace = true
|
||||
reqwest.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
url.workspace = true
|
||||
|
|
|
@ -88,6 +88,17 @@ impl From<&'static str> for AsyncBody {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryFrom<reqwest::Body> for AsyncBody {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: reqwest::Body) -> Result<Self, Self::Error> {
|
||||
value
|
||||
.as_bytes()
|
||||
.ok_or_else(|| anyhow::anyhow!("Underlying data is a stream"))
|
||||
.map(|bytes| Self::from_bytes(Bytes::copy_from_slice(bytes)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<Self>> From<Option<T>> for AsyncBody {
|
||||
fn from(body: Option<T>) -> Self {
|
||||
match body {
|
||||
|
|
|
@ -7,7 +7,10 @@ use derive_more::Deref;
|
|||
use http::HeaderValue;
|
||||
pub use http::{self, Method, Request, Response, StatusCode, Uri};
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use futures::{
|
||||
FutureExt as _,
|
||||
future::{self, BoxFuture},
|
||||
};
|
||||
use http::request::Builder;
|
||||
use parking_lot::Mutex;
|
||||
#[cfg(feature = "test-support")]
|
||||
|
@ -89,6 +92,14 @@ pub trait HttpClient: 'static + Send + Sync {
|
|||
fn as_fake(&self) -> &FakeHttpClient {
|
||||
panic!("called as_fake on {}", type_name::<Self>())
|
||||
}
|
||||
|
||||
fn send_multipart_form<'a>(
|
||||
&'a self,
|
||||
_url: &str,
|
||||
_request: reqwest::multipart::Form,
|
||||
) -> BoxFuture<'a, anyhow::Result<Response<AsyncBody>>> {
|
||||
future::ready(Err(anyhow!("not implemented"))).boxed()
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`HttpClient`] that may have a proxy.
|
||||
|
@ -140,31 +151,13 @@ impl HttpClient for HttpClientWithProxy {
|
|||
fn as_fake(&self) -> &FakeHttpClient {
|
||||
self.client.as_fake()
|
||||
}
|
||||
}
|
||||
|
||||
impl HttpClient for Arc<HttpClientWithProxy> {
|
||||
fn send(
|
||||
&self,
|
||||
req: Request<AsyncBody>,
|
||||
) -> BoxFuture<'static, anyhow::Result<Response<AsyncBody>>> {
|
||||
self.client.send(req)
|
||||
}
|
||||
|
||||
fn user_agent(&self) -> Option<&HeaderValue> {
|
||||
self.client.user_agent()
|
||||
}
|
||||
|
||||
fn proxy(&self) -> Option<&Url> {
|
||||
self.proxy.as_ref()
|
||||
}
|
||||
|
||||
fn type_name(&self) -> &'static str {
|
||||
self.client.type_name()
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-support")]
|
||||
fn as_fake(&self) -> &FakeHttpClient {
|
||||
self.client.as_fake()
|
||||
fn send_multipart_form<'a>(
|
||||
&'a self,
|
||||
url: &str,
|
||||
form: reqwest::multipart::Form,
|
||||
) -> BoxFuture<'a, anyhow::Result<Response<AsyncBody>>> {
|
||||
self.client.send_multipart_form(url, form)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,32 +268,6 @@ impl HttpClientWithUrl {
|
|||
}
|
||||
}
|
||||
|
||||
impl HttpClient for Arc<HttpClientWithUrl> {
|
||||
fn send(
|
||||
&self,
|
||||
req: Request<AsyncBody>,
|
||||
) -> BoxFuture<'static, anyhow::Result<Response<AsyncBody>>> {
|
||||
self.client.send(req)
|
||||
}
|
||||
|
||||
fn user_agent(&self) -> Option<&HeaderValue> {
|
||||
self.client.user_agent()
|
||||
}
|
||||
|
||||
fn proxy(&self) -> Option<&Url> {
|
||||
self.client.proxy.as_ref()
|
||||
}
|
||||
|
||||
fn type_name(&self) -> &'static str {
|
||||
self.client.type_name()
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-support")]
|
||||
fn as_fake(&self) -> &FakeHttpClient {
|
||||
self.client.as_fake()
|
||||
}
|
||||
}
|
||||
|
||||
impl HttpClient for HttpClientWithUrl {
|
||||
fn send(
|
||||
&self,
|
||||
|
@ -325,6 +292,14 @@ impl HttpClient for HttpClientWithUrl {
|
|||
fn as_fake(&self) -> &FakeHttpClient {
|
||||
self.client.as_fake()
|
||||
}
|
||||
|
||||
fn send_multipart_form<'a>(
|
||||
&'a self,
|
||||
url: &str,
|
||||
request: reqwest::multipart::Form,
|
||||
) -> BoxFuture<'a, anyhow::Result<Response<AsyncBody>>> {
|
||||
self.client.send_multipart_form(url, request)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_proxy_from_env() -> Option<Url> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue