Stop showing backtraces in default logging (#54660)
When using `.log_err()` or `.detach_and_log_err(cx)` or similar. See also https://github.com/zed-industries/zed/pull/36404, https://github.com/zed-industries/zed/pull/46383, https://github.com/zed-industries/zed/pull/44896, https://github.com/zed-industries/zed/pull/43917 and many more. Before, a https://github.com/zed-industries/zed/blob/77c74db82e35b2e3aeebea9629b644cf43137f16/crates/languages/src/go.rs#L568 line would show a backtrace even for `.context("no cached binary")?;` case, same as many other usages around the code: <img width="2032" height="1162" alt="before" src="https://github.com/user-attachments/assets/ef2188b3-74c9-4c86-82b8-9fdaed3c26ae" /> After: <img width="1896" height="157" alt="after" src="https://github.com/user-attachments/assets/a1067d9f-61f4-4833-aeab-9f1042d2514a" /> To show a backtrace as before, use `log_err_with_backtrace`. Release Notes: - Improved Zed's log output on errors
This commit is contained in:
1 parent
2a52236f9a
commit
e9d727015b
11 files changed
+156
-18
No files matched your search
@@ -2125,7 +2125,7 @@ impl AcpThread {
|
||||
let curr_status = mem::replace(&mut call.status, new_status);
|
||||
|
||||
if let ToolCallStatus::WaitingForConfirmation { respond_tx, .. } = curr_status {
|
||||
respond_tx.send(outcome).log_err();
|
||||
respond_tx.send(outcome).ok();
|
||||
} else if cfg!(debug_assertions) {
|
||||
panic!("tried to authorize an already authorized tool call");
|
||||
}
|
||||
|
||||
@@ -1309,7 +1309,9 @@ impl NativeAgentConnection {
|
||||
{
|
||||
response
|
||||
.send(outcome)
|
||||
.map(|_| anyhow!("authorization receiver was dropped"))
|
||||
.map_err(|_| {
|
||||
anyhow!("authorization receiver was dropped")
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
})
|
||||
|
||||
@@ -124,7 +124,7 @@ impl AskPassSession {
|
||||
ControlFlow::Continue(Ok(password))
|
||||
} else {
|
||||
if let Some(kill_tx) = kill_tx.lock().await.take() {
|
||||
kill_tx.send(()).log_err();
|
||||
kill_tx.send(()).ok();
|
||||
}
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
|
||||
@@ -738,7 +738,7 @@ pub trait InteractiveElement: Sized {
|
||||
fn key_context<C, E>(mut self, key_context: C) -> Self
|
||||
where
|
||||
C: TryInto<KeyContext, Error = E>,
|
||||
E: Debug,
|
||||
E: std::fmt::Display,
|
||||
{
|
||||
if let Some(key_context) = key_context.try_into().log_err() {
|
||||
self.interactivity().key_context = Some(key_context);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{App, PlatformDispatcher, PlatformScheduler};
|
||||
use futures::channel::mpsc;
|
||||
use futures::prelude::*;
|
||||
use gpui_util::TryFutureExt;
|
||||
use gpui_util::{TryFutureExt, TryFutureExtBacktrace};
|
||||
use scheduler::Instant;
|
||||
use scheduler::Scheduler;
|
||||
use std::{
|
||||
@@ -84,7 +84,7 @@ impl<T> Task<T> {
|
||||
impl<T, E> Task<Result<T, E>>
|
||||
where
|
||||
T: 'static,
|
||||
E: 'static + Debug,
|
||||
E: 'static + std::fmt::Display,
|
||||
{
|
||||
/// Run the task to completion in the background and log any errors that occur.
|
||||
#[track_caller]
|
||||
@@ -96,6 +96,22 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Task<Result<T, E>>
|
||||
where
|
||||
T: 'static,
|
||||
E: 'static + std::fmt::Debug,
|
||||
{
|
||||
/// Like [`Self::detach_and_log_err`], but uses `{:?}` formatting on failure so `anyhow::Error`
|
||||
/// values emit their full backtrace. Prefer `detach_and_log_err` unless a backtrace is wanted.
|
||||
#[track_caller]
|
||||
pub fn detach_and_log_err_with_backtrace(self, cx: &App) {
|
||||
let location = *core::panic::Location::caller();
|
||||
cx.foreground_executor()
|
||||
.spawn(self.log_tracked_err_with_backtrace(location))
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::future::Future for Task<T> {
|
||||
type Output = T;
|
||||
|
||||
|
||||
@@ -2237,7 +2237,13 @@ impl Dispatch<wl_data_device::WlDataDevice, ()> for WaylandClientStatePtr {
|
||||
let paths: SmallVec<[_; 2]> = file_list
|
||||
.lines()
|
||||
.filter_map(|path| Url::parse(path).log_err())
|
||||
.filter_map(|url| url.to_file_path().log_err())
|
||||
.filter_map(|url| match url.to_file_path() {
|
||||
Ok(url) => Some(url),
|
||||
Err(()) => {
|
||||
log::error!("Failed turn {url:?} into a file path");
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let position = Point::new(x.into(), y.into());
|
||||
|
||||
|
||||
@@ -908,7 +908,13 @@ impl X11Client {
|
||||
let paths: SmallVec<[_; 2]> = file_list
|
||||
.lines()
|
||||
.filter_map(|path| Url::parse(path).log_err())
|
||||
.filter_map(|url| url.to_file_path().log_err())
|
||||
.filter_map(|url| match url.to_file_path() {
|
||||
Ok(url) => Some(url),
|
||||
Err(()) => {
|
||||
log::error!("Failed turn {url:?} into a file path");
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let input = PlatformInput::FileDrop(FileDropEvent::Entered {
|
||||
position: state.xdnd_state.position,
|
||||
|
||||
+108
-7
@@ -79,6 +79,12 @@ pub trait ResultExt<E> {
|
||||
type Ok;
|
||||
|
||||
fn log_err(self) -> Option<Self::Ok>;
|
||||
/// Like [`ResultExt::log_err`], but uses `{:?}` formatting so `anyhow::Error` values emit their
|
||||
/// full backtrace. Reach for this only when a backtrace is genuinely wanted — most call sites
|
||||
/// should stick with `log_err` / `warn_on_err`, whose output is a single chained error message.
|
||||
fn log_err_with_backtrace(self) -> Option<Self::Ok>
|
||||
where
|
||||
E: std::fmt::Debug;
|
||||
/// Assert that this result should never be an error in development or tests.
|
||||
fn debug_assert_ok(self, reason: &str) -> Self;
|
||||
fn warn_on_err(self) -> Option<Self::Ok>;
|
||||
@@ -90,7 +96,7 @@ pub trait ResultExt<E> {
|
||||
|
||||
impl<T, E> ResultExt<E> for Result<T, E>
|
||||
where
|
||||
E: std::fmt::Debug,
|
||||
E: std::fmt::Display,
|
||||
{
|
||||
type Ok = T;
|
||||
|
||||
@@ -99,10 +105,28 @@ where
|
||||
self.log_with_level(log::Level::Error)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn log_err_with_backtrace(self) -> Option<T>
|
||||
where
|
||||
E: std::fmt::Debug,
|
||||
{
|
||||
match self {
|
||||
Ok(value) => Some(value),
|
||||
Err(error) => {
|
||||
log_error_with_caller(
|
||||
*Location::caller(),
|
||||
DebugAsDisplay(&error),
|
||||
log::Level::Error,
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn debug_assert_ok(self, reason: &str) -> Self {
|
||||
if let Err(error) = &self {
|
||||
debug_panic!("{reason} - {error:?}");
|
||||
debug_panic!("{reason} - {error:#}");
|
||||
}
|
||||
self
|
||||
}
|
||||
@@ -133,7 +157,7 @@ where
|
||||
|
||||
fn log_error_with_caller<E>(caller: core::panic::Location<'_>, error: E, level: log::Level)
|
||||
where
|
||||
E: std::fmt::Debug,
|
||||
E: std::fmt::Display,
|
||||
{
|
||||
#[cfg(not(windows))]
|
||||
let file = caller.file();
|
||||
@@ -156,7 +180,7 @@ where
|
||||
&log::Record::builder()
|
||||
.target(module_path.as_deref().unwrap_or(""))
|
||||
.module_path(file.as_deref())
|
||||
.args(format_args!("{:?}", error))
|
||||
.args(format_args!("{:#}", error))
|
||||
.file(Some(caller.file()))
|
||||
.line(Some(caller.line()))
|
||||
.level(level)
|
||||
@@ -164,10 +188,20 @@ where
|
||||
);
|
||||
}
|
||||
|
||||
pub fn log_err<E: std::fmt::Debug>(error: &E) {
|
||||
pub fn log_err<E: std::fmt::Display>(error: &E) {
|
||||
log_error_with_caller(*Location::caller(), error, log::Level::Error);
|
||||
}
|
||||
|
||||
// Forces `{:?}` formatting through a `Display`-bounded logging helper so `anyhow::Error` emits a
|
||||
// backtrace instead of the single-line chained message produced by its `Display`/`{:#}` forms.
|
||||
struct DebugAsDisplay<'a, E>(&'a E);
|
||||
|
||||
impl<E: std::fmt::Debug> std::fmt::Display for DebugAsDisplay<'_, E> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TryFutureExt {
|
||||
fn log_err(self) -> LogErrorFuture<Self>
|
||||
where
|
||||
@@ -185,10 +219,25 @@ pub trait TryFutureExt {
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
/// `{:?}`-formatting companion to [`TryFutureExt`]; emits a backtrace for `anyhow::Error`. Prefer
|
||||
/// [`TryFutureExt`] unless a backtrace is genuinely wanted.
|
||||
pub trait TryFutureExtBacktrace {
|
||||
fn log_err_with_backtrace(self) -> LogErrorWithBacktraceFuture<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn log_tracked_err_with_backtrace(
|
||||
self,
|
||||
location: core::panic::Location<'static>,
|
||||
) -> LogErrorWithBacktraceFuture<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<F, T, E> TryFutureExt for F
|
||||
where
|
||||
F: Future<Output = Result<T, E>>,
|
||||
E: std::fmt::Debug,
|
||||
E: std::fmt::Display,
|
||||
{
|
||||
#[track_caller]
|
||||
fn log_err(self) -> LogErrorFuture<Self>
|
||||
@@ -223,10 +272,62 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T, E> TryFutureExtBacktrace for F
|
||||
where
|
||||
F: Future<Output = Result<T, E>>,
|
||||
E: std::fmt::Debug,
|
||||
{
|
||||
#[track_caller]
|
||||
fn log_err_with_backtrace(self) -> LogErrorWithBacktraceFuture<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let location = Location::caller();
|
||||
LogErrorWithBacktraceFuture(self, log::Level::Error, *location)
|
||||
}
|
||||
|
||||
fn log_tracked_err_with_backtrace(
|
||||
self,
|
||||
location: core::panic::Location<'static>,
|
||||
) -> LogErrorWithBacktraceFuture<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
LogErrorWithBacktraceFuture(self, log::Level::Error, location)
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub struct LogErrorFuture<F>(F, log::Level, core::panic::Location<'static>);
|
||||
|
||||
impl<F, T, E> Future for LogErrorFuture<F>
|
||||
where
|
||||
F: Future<Output = Result<T, E>>,
|
||||
E: std::fmt::Display,
|
||||
{
|
||||
type Output = Option<T>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
let level = self.1;
|
||||
let location = self.2;
|
||||
let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };
|
||||
match inner.poll(cx) {
|
||||
Poll::Ready(output) => Poll::Ready(match output {
|
||||
Ok(output) => Some(output),
|
||||
Err(error) => {
|
||||
log_error_with_caller(location, error, level);
|
||||
None
|
||||
}
|
||||
}),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub struct LogErrorWithBacktraceFuture<F>(F, log::Level, core::panic::Location<'static>);
|
||||
|
||||
impl<F, T, E> Future for LogErrorWithBacktraceFuture<F>
|
||||
where
|
||||
F: Future<Output = Result<T, E>>,
|
||||
E: std::fmt::Debug,
|
||||
@@ -241,7 +342,7 @@ where
|
||||
Poll::Ready(output) => Poll::Ready(match output {
|
||||
Ok(output) => Some(output),
|
||||
Err(error) => {
|
||||
log_error_with_caller(location, error, level);
|
||||
log_error_with_caller(location, DebugAsDisplay(&error), level);
|
||||
None
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -130,7 +130,7 @@ impl TaskStore {
|
||||
.payload
|
||||
.task_variables
|
||||
.into_iter()
|
||||
.filter_map(|(k, v)| Some((k.parse().log_err()?, v))),
|
||||
.filter_map(|(k, v)| Some((k.parse().ok()?, v))),
|
||||
);
|
||||
|
||||
let snapshot = location.buffer.read(cx).snapshot();
|
||||
|
||||
@@ -254,6 +254,14 @@ impl RelPath {
|
||||
#[derive(Debug)]
|
||||
pub struct StripPrefixError;
|
||||
|
||||
impl std::fmt::Display for StripPrefixError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("prefix not found")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for StripPrefixError {}
|
||||
|
||||
impl ToOwned for RelPath {
|
||||
type Owned = RelPathBuf;
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ use gpui::{
|
||||
use std::any::TypeId;
|
||||
use theme::CLIENT_SIDE_DECORATION_ROUNDING;
|
||||
use ui::{Divider, Indicator, Tooltip, prelude::*};
|
||||
use util::ResultExt;
|
||||
|
||||
pub trait StatusItemView: Render {
|
||||
/// Event callback that is triggered when the active pane item changes.
|
||||
@@ -246,7 +245,7 @@ impl StatusBar {
|
||||
self.left_items
|
||||
.iter()
|
||||
.chain(self.right_items.iter())
|
||||
.find_map(|item| item.to_any().downcast().log_err())
|
||||
.find_map(|item| item.to_any().downcast().ok())
|
||||
}
|
||||
|
||||
pub fn position_of_item<T>(&self) -> Option<usize>
|
||||
|
||||
Reference in new issue
Block a user