This commit is contained in:
Brandon Thomas committed 2026-04-01 20:34:47 -04:00
1 parent f5dbbac55d
commit 3163748052
2 files changed
+38 -89

No files matched your search

@@ -1,5 +1,4 @@
use chrono::{DateTime, Utc};
use std::fmt::{Debug, Display};
use crate::notification::generate_deduplication_key::generate_deduplication_key;
use crate::notification::notification_details_builder::NotificationDetailsBuilder;
@@ -49,93 +48,11 @@ pub struct NotificationDetails {
}
impl NotificationDetails {
pub fn builder(title: String) -> NotificationDetailsBuilder {
pub fn from_title(title: String) -> NotificationDetailsBuilder {
NotificationDetailsBuilder::from_title(title)
}
pub fn to_deduplication_key(&self) -> String {
generate_deduplication_key(self)
}
/// Create a notification from any error type.
///
/// Formats the error into a structured description that includes:
/// - The error message
/// - The error's source chain (if any)
/// - A backtrace (if available via `std::backtrace`)
/// - The timestamp of the event
///
/// Note: this does not retain the error object itself. Use
/// `NotificationDetailsBuilder::from_title().set_error()` to attach an error.
#[deprecated(note = "Use NotificationDetailsBuilder::from_title().set_error() instead")]
pub fn from_error_info<E: Debug + Display>(error: &E) -> Self {
let title = format!("{}", error);
// Truncate the title to a reasonable length for alert titles.
let title = if title.len() > 200 {
format!("{}...", &title[..197])
} else {
title
};
let event_time = Utc::now();
let mut description_parts: Vec<String> = Vec::new();
description_parts.push(format!("Event time: {}", event_time.format("%Y-%m-%d %H:%M:%S UTC")));
description_parts.push(String::new());
description_parts.push(format!("Error: {}", error));
// Include the Debug representation if it differs from Display (often has more detail).
let debug_repr = format!("{:?}", error);
let display_repr = format!("{}", error);
if debug_repr != display_repr {
description_parts.push(String::new());
description_parts.push(format!("Debug: {}", debug_repr));
}
// Attempt to walk the error source chain.
// NB: We use the Debug trait here since we can't require std::error::Error
// (that would require E: 'static + Error which is too restrictive for callers).
// Try to capture a backtrace from the current call site.
#[cfg(feature = "backtrace")]
{
let bt = std::backtrace::Backtrace::capture();
if bt.status() == std::backtrace::BacktraceStatus::Captured {
description_parts.push(String::new());
description_parts.push(format!("Backtrace:\n{}", bt));
}
}
let description = description_parts.join("\n");
Self {
title,
description: Some(description),
urgency: None,
event_time,
maybe_error: None,
is_from_error: true,
http_method: None,
http_path: None,
http_status_code: None,
user_token: None,
media_file_token: None,
inference_job_token: None,
third_party_id: None,
}
}
/// Create a notification from an error, with a custom title prefix.
#[deprecated(note = "Use NotificationDetailsBuilder::from_title().set_error() instead")]
pub fn from_error_info_with_context<E: Debug + Display>(context: &str, error: &E) -> Self {
#[allow(deprecated)]
let mut notification = Self::from_error_info(error);
notification.title = format!("{}: {}", context, notification.title);
if notification.title.len() > 200 {
notification.title = format!("{}...", &notification.title[..197]);
}
notification
}
}
@@ -51,13 +51,45 @@ impl NotificationDetailsBuilder {
/// Use `from_title().set_error()` to attach the actual error.
#[deprecated(note = "Use from_title().set_error() instead")]
pub fn from_error_info<E: Debug + Display>(error: &E) -> Self {
#[allow(deprecated)]
let details = NotificationDetails::from_error_info(error);
let title = format!("{}", error);
let title = if title.len() > 200 {
format!("{}...", &title[..197])
} else {
title
};
let event_time = Utc::now();
let mut description_parts: Vec<String> = Vec::new();
description_parts.push(format!("Event time: {}", event_time.format("%Y-%m-%d %H:%M:%S UTC")));
description_parts.push(String::new());
description_parts.push(format!("Error: {}", error));
let debug_repr = format!("{:?}", error);
let display_repr = format!("{}", error);
if debug_repr != display_repr {
description_parts.push(String::new());
description_parts.push(format!("Debug: {}", debug_repr));
}
#[cfg(feature = "backtrace")]
{
let bt = std::backtrace::Backtrace::capture();
if bt.status() == std::backtrace::BacktraceStatus::Captured {
description_parts.push(String::new());
description_parts.push(format!("Backtrace:\n{}", bt));
}
}
let description = description_parts.join("\n");
Self {
title: details.title,
description: details.description,
title,
description: Some(description),
urgency: None,
event_time: details.event_time,
event_time,
maybe_error: None,
is_from_error: true,
http_method: None,