Skip to content

Commit 58824dd

Browse files
Show the error source chain in builtins::on_error (#386)
1 parent 588bbe6 commit 58824dd

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()
@@ -116,14 +117,19 @@ pub async fn on_error<U, E: std::fmt::Display + std::fmt::Debug>(
116117
description,
117118
);
118119
}
119-
crate::FrameworkError::CommandCheckFailed { ctx, error } => {
120-
tracing::error!(
121-
"A command check failed in command {} for user {}: {:?}",
120+
crate::FrameworkError::CommandCheckFailed { ctx, error } => match error {
121+
Some(error) => tracing::error!(
122+
"A command check failed in command {} for user {}: {}",
122123
ctx.command().name,
123124
ctx.author().name,
124-
error,
125-
);
126-
}
125+
display_error(error),
126+
),
127+
None => tracing::error!(
128+
"A command check failed in command {} for user {}",
129+
ctx.command().name,
130+
ctx.author().name,
131+
),
132+
},
127133
crate::FrameworkError::CooldownHit {
128134
remaining_cooldown,
129135
ctx,
@@ -195,7 +201,7 @@ pub async fn on_error<U, E: std::fmt::Display + std::fmt::Debug>(
195201
tracing::error!(
196202
"Dynamic prefix failed for message {:?}: {}",
197203
msg.content,
198-
error
204+
display_error(error)
199205
);
200206
}
201207
crate::FrameworkError::UnknownCommand {
@@ -213,7 +219,10 @@ pub async fn on_error<U, E: std::fmt::Display + std::fmt::Debug>(
213219
tracing::warn!("received unknown interaction \"{}\"", interaction.data.name);
214220
}
215221
crate::FrameworkError::NonCommandMessage { error, .. } => {
216-
tracing::warn!("error in non-command message handler: {}", error);
222+
tracing::warn!(
223+
"error in non-command message handler: {}",
224+
display_error(error)
225+
);
217226
}
218227
crate::FrameworkError::__NonExhaustive(unreachable) => match unreachable {},
219228
}
@@ -328,3 +337,26 @@ pub async fn servers<U, E>(ctx: crate::Context<'_, U, E>) -> Result<(), serenity
328337
ctx.send(reply).await?;
329338
Ok(())
330339
}
340+
341+
/// Helper function to display an `impl Into<Box<dyn std::error::Error>>` and its chain of causes.
342+
fn display_error(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> impl Display {
343+
struct DisplayError(Box<dyn std::error::Error + Send + Sync>);
344+
345+
impl Display for DisplayError {
346+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347+
let mut e: &(dyn std::error::Error + 'static) = &*self.0;
348+
349+
Display::fmt(e, f)?;
350+
351+
while let Some(new_e) = e.source() {
352+
f.write_str(": ")?;
353+
Display::fmt(new_e, f)?;
354+
e = new_e;
355+
}
356+
357+
Ok(())
358+
}
359+
}
360+
361+
DisplayError(e.into())
362+
}

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)