mirror of
https://github.com/localsend/localsend.git
synced 2026-08-07 07:14:52 +00:00
feat: more descriptive debug error
This commit is contained in:
@@ -11,6 +11,7 @@ use crate::model::discovery::{MulticastMessageV2, ProtocolType};
|
||||
use crate::multicast::{
|
||||
self, InterfaceFilter, MulticastConfig, MulticastDevice, MulticastEvent, MulticastHandle,
|
||||
};
|
||||
use crate::util::error::ErrorChain;
|
||||
use futures_util::StreamExt;
|
||||
use std::collections::HashSet;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
@@ -425,7 +426,10 @@ async fn answer_announcement(
|
||||
) {
|
||||
Ok(client) => client,
|
||||
Err(err) => {
|
||||
tracing::error!("Could not create the client to answer {host}: {err:#}");
|
||||
tracing::error!(
|
||||
"Could not create the client to answer {host}: {}",
|
||||
ErrorChain(&err)
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -448,7 +452,12 @@ async fn answer_announcement(
|
||||
state.found(device).await;
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::debug!("Could not register with announcing device {host}: {err:#}");
|
||||
let url = format!("{}://{host}:{}", message.protocol.as_str(), message.port);
|
||||
tracing::debug!(
|
||||
"Could not register with announcing device {} ({url}): {}",
|
||||
message.alias,
|
||||
ErrorChain(&err),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
/// Displays an error together with its whole source chain, joined by `: `.
|
||||
///
|
||||
/// Plain [`Display`] only prints the outermost error, which hides the actual
|
||||
/// cause for wrappers like `reqwest::Error` ("error sending request for url ...").
|
||||
pub struct ErrorChain<'a>(pub &'a dyn Error);
|
||||
|
||||
impl Display for ErrorChain<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)?;
|
||||
|
||||
let mut source = self.0.source();
|
||||
while let Some(err) = source {
|
||||
write!(f, ": {err}")?;
|
||||
source = err.source();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TestError(&'static str, Option<Box<TestError>>);
|
||||
|
||||
impl Display for TestError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for TestError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
self.1.as_ref().map(|err| err as &(dyn Error + 'static))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn formats_the_whole_chain() {
|
||||
let err = TestError(
|
||||
"outer",
|
||||
Some(Box::new(TestError(
|
||||
"middle",
|
||||
Some(Box::new(TestError("inner", None))),
|
||||
))),
|
||||
);
|
||||
|
||||
assert_eq!(ErrorChain(&err).to_string(), "outer: middle: inner");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn formats_a_single_error() {
|
||||
assert_eq!(ErrorChain(&TestError("only", None)).to_string(), "only");
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod base64;
|
||||
pub mod error;
|
||||
pub mod filename;
|
||||
pub(crate) mod time;
|
||||
|
||||
@@ -7,6 +7,7 @@ use localsend::discovery::{
|
||||
};
|
||||
use localsend::model::discovery::{DeviceType, ProtocolType};
|
||||
use localsend::multicast::{DEFAULT_MULTICAST_GROUP_V6, InterfaceFilter, MulticastDevice};
|
||||
use localsend::util::error::ErrorChain;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::{Mutex, mpsc, oneshot};
|
||||
@@ -302,7 +303,11 @@ impl RsDiscovery {
|
||||
match self.instance.handle.discover(&host, port, protocol).await {
|
||||
Ok(found) => found.map(rs_stored_device),
|
||||
Err(err) => {
|
||||
tracing::debug!("Could not discover {host}:{port}: {err:#}");
|
||||
tracing::debug!(
|
||||
"Could not discover {}://{host}:{port}: {}",
|
||||
protocol.as_str(),
|
||||
ErrorChain(&err)
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ pub use localsend::http::dto::{
|
||||
};
|
||||
use localsend::model::discovery::ProtocolType;
|
||||
use localsend::reqwest;
|
||||
use localsend::util::error::ErrorChain;
|
||||
|
||||
pub struct RsHttpClient {
|
||||
inner: localsend::http::client::LsHttpClient,
|
||||
@@ -231,7 +232,7 @@ impl From<ClientError> for RsHttpClientError {
|
||||
status: e.status,
|
||||
message: e.message,
|
||||
},
|
||||
ClientError::Reqwest(e) => RsHttpClientError::Reqwest(error_chain(&e)),
|
||||
ClientError::Reqwest(e) => RsHttpClientError::Reqwest(ErrorChain(&e).to_string()),
|
||||
ClientError::Json(e) => RsHttpClientError::Json(e.to_string()),
|
||||
ClientError::Io(e) => RsHttpClientError::Io(e.to_string()),
|
||||
ClientError::Other(e) => RsHttpClientError::Other(e.to_string()),
|
||||
@@ -240,21 +241,6 @@ impl From<ClientError> for RsHttpClientError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders an error together with everything that caused it.
|
||||
///
|
||||
/// [`reqwest::Error`] alone only says "error sending request for url (...)".
|
||||
pub(crate) fn error_chain(e: &dyn std::error::Error) -> String {
|
||||
use std::fmt::Write;
|
||||
|
||||
let mut message = e.to_string();
|
||||
let mut source = e.source();
|
||||
while let Some(current) = source {
|
||||
let _ = write!(message, ": {current}");
|
||||
source = current.source();
|
||||
}
|
||||
message
|
||||
}
|
||||
|
||||
#[frb(mirror(LsHttpClientVersion))]
|
||||
pub enum _LsHttpClientVersion {
|
||||
V2,
|
||||
|
||||
Reference in New Issue
Block a user