use std::io::{self, Write};
#[macro_export]
macro_rules! alert_critical {
($message:expr, $fix:expr, $($action:expr),+) => {
{
let actions: Vec<String> = vec![$($action.to_string()),+];
let action_str = actions.join("\n đ ");
$crate::utils::alert::critical_impl($message, Some(&format!("{}\n đ {}", $fix, action_str)));
}
};
($message:expr, $fix:expr) => {
$crate::utils::alert::critical_impl($message, Some($fix));
};
($format_str:expr, $($arg:expr),+ $(,)?) => {
{
let msg = format!($format_str, $($arg),+);
$crate::utils::alert::critical_impl(&msg, None::<&str>);
}
};
($message:expr) => {
$crate::utils::alert::critical_impl($message, None::<&str>);
};
}
#[macro_export]
macro_rules! alert_warning {
($message:expr, $fix:expr) => {
$crate::utils::alert::warning_impl($message, Some($fix));
};
($format_str:expr, $($arg:expr),+ $(,)?) => {
{
let msg = format!($format_str, $($arg),+);
$crate::utils::alert::warning_impl(&msg, None::<&str>);
}
};
($message:expr) => {
$crate::utils::alert::warning_impl($message, None::<&str>);
};
}
#[macro_export]
macro_rules! alert_info {
($message:expr) => {
$crate::utils::alert::info_impl($message);
};
($($arg:tt)*) => {
{
let msg = format!($($arg)*);
$crate::utils::alert::info_impl(&msg);
}
};
}
#[macro_export]
macro_rules! alert_success {
($message:expr) => {
$crate::utils::alert::success_impl($message);
};
($($arg:tt)*) => {
{
let msg = format!($($arg)*);
$crate::utils::alert::success_impl(&msg);
}
};
}
#[macro_export]
macro_rules! alert_debug {
($message:expr) => {
$crate::utils::alert::debug_impl($message);
};
($($arg:tt)*) => {
{
let msg = format!($($arg)*);
$crate::utils::alert::debug_impl(&msg);
}
};
}
#[macro_export]
macro_rules! alert {
($severity:expr, $message:expr) => {
$crate::utils::alert::custom_impl($severity, $message, None::<&str>, None::<&str>);
};
($severity:expr, $message:expr, $stop:expr, $fix:expr) => {
$crate::utils::alert::custom_impl($severity, $message, Some($stop), Some($fix));
};
($severity:expr, $message:expr, $stop:expr, $fix:expr, $($action:expr),+) => {
{
let actions: Vec<String> = vec![$($action.to_string()),+];
let action_str = actions.join("\n đ ");
$crate::utils::alert::custom_impl($severity, $message, Some($stop), Some(&format!("{}\n đ {}", $fix, action_str)));
}
};
}
pub fn critical_impl(message: &str, fix: Option<&str>) {
if let Some(fix_msg) = fix {
try_slog_error(&format!(
"{}\n â ī¸ STOP: Cannot proceed\n đĄ FIX: {}",
message, fix_msg
));
eprintln!(
"đ¨ {}\n â ī¸ STOP: Cannot proceed\n đĄ FIX: {}",
message, fix_msg
);
} else {
try_slog_error(&format!(
"{}\n â ī¸ STOP: Cannot proceed\n đĄ FIX: Investigate and resolve",
message
));
eprintln!(
"đ¨ {}\n â ī¸ STOP: Cannot proceed\n đĄ FIX: Investigate and resolve",
message
);
}
}
pub fn warning_impl(message: &str, fix: Option<&str>) {
if let Some(fix_msg) = fix {
try_slog_warn(&format!(
"{}\n â ī¸ WARNING: Investigate before proceeding\n đĄ FIX: {}",
message, fix_msg
));
eprintln!(
"â ī¸ {}\n â ī¸ WARNING: Investigate before proceeding\n đĄ FIX: {}",
message, fix_msg
);
} else {
try_slog_warn(&format!(
"{}\n â ī¸ WARNING: Investigate before proceeding\n đĄ FIX: Check and resolve",
message
));
eprintln!(
"â ī¸ {}\n â ī¸ WARNING: Investigate before proceeding\n đĄ FIX: Check and resolve",
message
);
}
}
pub fn info_impl(message: &str) {
try_slog_info(message);
eprintln!("âšī¸ {}", message);
}
pub fn success_impl(message: &str) {
try_slog_info(&format!("â
{}", message));
eprintln!("â
{}", message);
}
pub fn debug_impl(message: &str) {
try_slog_debug(message);
eprintln!("đ {}", message);
}
pub fn custom_impl(severity: &str, message: &str, stop: Option<&str>, fix: Option<&str>) {
if let (Some(stop_msg), Some(fix_msg)) = (stop, fix) {
try_slog_warn(&format!(
"{} {}\n {} {}\n đĄ FIX: {}",
severity, message, severity, stop_msg, fix_msg
));
eprintln!(
"{} {}\n {} {}\n đĄ FIX: {}",
severity, message, severity, stop_msg, fix_msg
);
} else {
try_slog_info(&format!("{} {}", severity, message));
eprintln!("{} {}", severity, message);
}
}
fn try_slog_error(msg: &str) {
let _ = std::panic::catch_unwind(|| {
slog_scope::error!("{}", msg);
});
}
fn try_slog_warn(msg: &str) {
let _ = std::panic::catch_unwind(|| {
slog_scope::warn!("{}", msg);
});
}
fn try_slog_info(msg: &str) {
let _ = std::panic::catch_unwind(|| {
slog_scope::info!("{}", msg);
});
}
fn try_slog_debug(msg: &str) {
let _ = std::panic::catch_unwind(|| {
slog_scope::debug!("{}", msg);
});
}
pub fn write_alert<W: Write>(
writer: &mut W, severity: &str, message: &str, stop: Option<&str>, fix: Option<&str>,
) -> io::Result<()> {
if let (Some(stop_msg), Some(fix_msg)) = (stop, fix) {
writeln!(
writer,
"{severity} {message}\n {severity} {stop_msg}\n đĄ FIX: {fix_msg}"
)?;
} else if let Some(stop_msg) = stop {
writeln!(writer, "{severity} {message}\n {severity} {stop_msg}")?;
} else {
writeln!(writer, "{severity} {message}")?;
}
Ok(())
}
#[cfg(test)]
#[allow(clippy::panic)] mod tests {
use super::*;
#[test]
fn test_alert_critical() {
alert_critical!("Test critical error");
alert_critical!("Test critical error", "Test fix");
alert_critical!("Test critical error", "Test fix", "Action 1", "Action 2");
}
#[test]
fn test_alert_warning() {
alert_warning!("Test warning");
alert_warning!("Test warning", "Test fix");
alert_warning!(
"Test warning: {} - Actions: {}, {}",
"Test fix",
"Action 1",
"Action 2"
);
}
#[test]
fn test_alert_info() {
alert_info!("Test info");
alert_info!("Test info: {}, {}", "Detail 1", "Detail 2");
}
#[test]
fn test_alert_success() {
alert_success!("Test success");
alert_success!("Test success: {}, {}", "Detail 1", "Detail 2");
}
#[test]
fn test_alert_debug() {
alert_debug!("Test debug");
alert_debug!("Test debug: {}", "value");
}
#[test]
fn test_alert_custom() {
alert!("đ¨", "Custom critical");
alert!(
"đ¨",
"Custom critical",
"STOP: Cannot proceed",
"FIX: Resolve issue"
);
alert!(
"đ¨",
"Custom critical",
"STOP: Cannot proceed",
"FIX: Resolve issue",
"Action 1",
"Action 2"
);
}
#[test]
fn test_write_alert() {
let mut buffer = Vec::new();
write_alert(&mut buffer, "đ¨", "Test error", None, None).unwrap();
let output = String::from_utf8_lossy(&buffer);
assert!(output.contains("đ¨ Test error"));
buffer.clear();
write_alert(
&mut buffer,
"đ¨",
"Test error",
Some("STOP: Cannot proceed"),
None,
)
.unwrap();
let output = String::from_utf8_lossy(&buffer);
assert!(output.contains("đ¨ Test error"));
assert!(output.contains("STOP: Cannot proceed"));
buffer.clear();
write_alert(
&mut buffer,
"đ¨",
"Test error",
Some("STOP: Cannot proceed"),
Some("FIX: Resolve issue"),
)
.unwrap();
let output = String::from_utf8_lossy(&buffer);
assert!(output.contains("đ¨ Test error"));
assert!(output.contains("STOP: Cannot proceed"));
assert!(output.contains("FIX: Resolve issue"));
}
}