Skip to content

Commit 3c01afc

Browse files
SabrinaJewsonarqunis
authored andcommitted
Show the error source chain in builtins::on_error (#386)
1 parent fbf89f1 commit 3c01afc

File tree

2 files changed

+45
-13
lines changed

2 files changed

+45
-13
lines changed

src/builtins/mod.rs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod paginate;
1212
pub use paginate::*;
1313

1414
use crate::{serenity::CreateAllowedMentions, serenity_prelude as serenity, CreateReply};
15+
use std::fmt::{self, Display};
1516

1617
/// An error handler that logs errors either via the [`tracing`] crate or via a Discord message. Set
1718
/// up a logger like tracing subscriber
@@ -29,20 +30,20 @@ use crate::{serenity::CreateAllowedMentions, serenity_prelude as serenity, Creat
2930
/// }
3031
/// # };
3132
/// ```
32-
pub async fn on_error<U, E: std::fmt::Display + std::fmt::Debug>(
33+
pub async fn on_error<U, E: Into<Box<dyn std::error::Error + Send + Sync>>>(
3334
error: crate::FrameworkError<'_, U, E>,
3435
) -> Result<(), serenity::Error> {
3536
match error {
3637
crate::FrameworkError::Setup { error, .. } => {
37-
eprintln!("Error in user data setup: {}", error);
38+
eprintln!("Error in user data setup: {}", display_error(error));
3839
}
3940
crate::FrameworkError::EventHandler { error, event, .. } => tracing::error!(
4041
"User event event handler encountered an error on {} event: {}",
4142
event.snake_case_name(),
42-
error
43+
display_error(error)
4344
),
4445
crate::FrameworkError::Command { ctx, error } => {
45-
let error = error.to_string();
46+
let error = display_error(error).to_string();
4647
eprintln!("An error occured in a command: {}", error);
4748

4849
let mentions = CreateAllowedMentions::new()
@@ -118,14 +119,19 @@ pub async fn on_error<U, E: std::fmt::Display + std::fmt::Debug>(
118119
description,
119120
);
120121
}
121-
crate::FrameworkError::CommandCheckFailed { ctx, error } => {
122-
tracing::error!(
123-
"A command check failed in command {} for user {}: {:?}",
122+
crate::FrameworkError::CommandCheckFailed { ctx, error } => match error {
123+
Some(error) => tracing::error!(
124+
"A command check failed in command {} for user {}: {}",
124125
ctx.command().name,
125126
ctx.author().name,
126-
error,
127-
);
128-
}
127+
display_error(error),
128+
),
129+
None => tracing::error!(
130+
"A command check failed in command {} for user {}",
131+
ctx.command().name,
132+
ctx.author().name,
133+
),
134+
},
129135
crate::FrameworkError::CooldownHit {
130136
remaining_cooldown,
131137
ctx,
@@ -197,7 +203,7 @@ pub async fn on_error<U, E: std::fmt::Display + std::fmt::Debug>(
197203
tracing::error!(
198204
"Dynamic prefix failed for message {:?}: {}",
199205
msg.content,
200-
error
206+
display_error(error)
201207
);
202208
}
203209
crate::FrameworkError::UnknownCommand {
@@ -215,7 +221,10 @@ pub async fn on_error<U, E: std::fmt::Display + std::fmt::Debug>(
215221
tracing::warn!("received unknown interaction \"{}\"", interaction.data.name);
216222
}
217223
crate::FrameworkError::NonCommandMessage { error, .. } => {
218-
tracing::warn!("error in non-command message handler: {}", error);
224+
tracing::warn!(
225+
"error in non-command message handler: {}",
226+
display_error(error)
227+
);
219228
}
220229
crate::FrameworkError::__NonExhaustive(unreachable) => match unreachable {},
221230
}
@@ -330,3 +339,26 @@ pub async fn servers<U, E>(ctx: crate::Context<'_, U, E>) -> Result<(), serenity
330339
ctx.send(reply).await?;
331340
Ok(())
332341
}
342+
343+
/// Helper function to display an `impl Into<Box<dyn std::error::Error>>` and its chain of causes.
344+
fn display_error(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> impl Display {
345+
struct DisplayError(Box<dyn std::error::Error + Send + Sync>);
346+
347+
impl Display for DisplayError {
348+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349+
let mut e: &(dyn std::error::Error + 'static) = &*self.0;
350+
351+
Display::fmt(e, f)?;
352+
353+
while let Some(new_e) = e.source() {
354+
f.write_str(": ")?;
355+
Display::fmt(new_e, f)?;
356+
e = new_e;
357+
}
358+
359+
Ok(())
360+
}
361+
}
362+
363+
DisplayError(e.into())
364+
}

src/structs/framework_options.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl<U, E> FrameworkOptions<U, E> {
9292
impl<U, E> Default for FrameworkOptions<U, E>
9393
where
9494
U: Send + Sync,
95-
E: std::fmt::Display + std::fmt::Debug + Send,
95+
E: Into<Box<dyn std::error::Error + Send + Sync>> + Send,
9696
{
9797
fn default() -> Self {
9898
#[allow(deprecated)] // we need to set the listener field

0 commit comments

Comments
 (0)