1use std::io::{self, Write};
38
39#[macro_export]
57macro_rules! alert_critical {
58 ($message:expr, $fix:expr, $($action:expr),+) => {
59 {
60 let actions: Vec<String> = vec![$($action.to_string()),+];
61 let action_str = actions.join("\n đ ");
62 $crate::alert::_alert_critical_impl($message, Some(&format!("{}\n đ {}", $fix, action_str)));
63 }
64 };
65 ($message:expr, $fix:expr) => {
66 $crate::alert::_alert_critical_impl($message, Some($fix));
67 };
68 ($format_str:expr, $($arg:expr),+ $(,)?) => {
69 {
70 let msg = format!($format_str, $($arg),+);
71 $crate::alert::_alert_critical_impl(&msg, None::<&str>);
72 }
73 };
74 ($message:expr) => {
75 $crate::alert::_alert_critical_impl($message, None::<&str>);
76 };
77}
78
79#[macro_export]
97macro_rules! alert_warning {
98 ($message:expr, $fix:expr) => {
99 $crate::alert::_alert_warning_impl($message, Some($fix));
100 };
101 ($format_str:expr, $($arg:expr),+ $(,)?) => {
102 {
103 let msg = format!($format_str, $($arg),+);
104 $crate::alert::_alert_warning_impl(&msg, None::<&str>);
105 }
106 };
107 ($message:expr) => {
108 $crate::alert::_alert_warning_impl($message, None::<&str>);
109 };
110}
111
112#[macro_export]
129macro_rules! alert_info {
130 ($message:expr) => {
131 $crate::alert::_alert_info_impl($message);
132 };
133 ($($arg:tt)*) => {
134 {
135 let msg = format!($($arg)*);
136 $crate::alert::_alert_info_impl(&msg);
137 }
138 };
139}
140
141#[macro_export]
158macro_rules! alert_success {
159 ($message:expr) => {
160 $crate::alert::_alert_success_impl($message);
161 };
162 ($($arg:tt)*) => {
163 {
164 let msg = format!($($arg)*);
165 $crate::alert::_alert_success_impl(&msg);
166 }
167 };
168}
169
170#[macro_export]
187macro_rules! alert_debug {
188 ($message:expr) => {
189 $crate::alert::_alert_debug_impl($message);
190 };
191 ($($arg:tt)*) => {
192 {
193 let msg = format!($($arg)*);
194 $crate::alert::_alert_debug_impl(&msg);
195 }
196 };
197}
198
199#[macro_export]
218macro_rules! alert {
219 ($severity:expr, $message:expr) => {
220 $crate::alert::_alert_custom_impl($severity, $message, None::<&str>, None::<&str>);
221 };
222 ($severity:expr, $message:expr, $stop:expr, $fix:expr) => {
223 $crate::alert::_alert_custom_impl($severity, $message, Some($stop), Some($fix));
224 };
225 ($severity:expr, $message:expr, $stop:expr, $fix:expr, $($action:expr),+) => {
226 {
227 let actions: Vec<String> = vec![$($action.to_string()),+];
228 let action_str = actions.join("\n đ ");
229 $crate::alert::_alert_custom_impl($severity, $message, Some($stop), Some(&format!("{}\n đ {}", $fix, action_str)));
230 }
231 };
232}
233
234#[allow(clippy::module_name_repetitions)]
238pub fn _alert_critical_impl(message: &str, fix: Option<&str>) {
239 if let Some(fix_msg) = fix {
240 _try_slog_error(&format!(
241 "{}\n â ī¸ STOP: Cannot proceed\n đĄ FIX: {}",
242 message, fix_msg
243 ));
244 eprintln!(
245 "đ¨ {}\n â ī¸ STOP: Cannot proceed\n đĄ FIX: {}",
246 message, fix_msg
247 );
248 } else {
249 _try_slog_error(&format!(
250 "{}\n â ī¸ STOP: Cannot proceed\n đĄ FIX: Investigate and resolve",
251 message
252 ));
253 eprintln!(
254 "đ¨ {}\n â ī¸ STOP: Cannot proceed\n đĄ FIX: Investigate and resolve",
255 message
256 );
257 }
258}
259
260#[allow(clippy::module_name_repetitions)]
262pub fn _alert_warning_impl(message: &str, fix: Option<&str>) {
263 if let Some(fix_msg) = fix {
264 _try_slog_warn(&format!(
265 "{}\n â ī¸ WARNING: Investigate before proceeding\n đĄ FIX: {}",
266 message, fix_msg
267 ));
268 eprintln!(
269 "â ī¸ {}\n â ī¸ WARNING: Investigate before proceeding\n đĄ FIX: {}",
270 message, fix_msg
271 );
272 } else {
273 _try_slog_warn(&format!(
274 "{}\n â ī¸ WARNING: Investigate before proceeding\n đĄ FIX: Check and resolve",
275 message
276 ));
277 eprintln!(
278 "â ī¸ {}\n â ī¸ WARNING: Investigate before proceeding\n đĄ FIX: Check and resolve",
279 message
280 );
281 }
282}
283
284#[allow(clippy::module_name_repetitions)]
286pub fn _alert_info_impl(message: &str) {
287 _try_slog_info(message);
288 eprintln!("âšī¸ {}", message);
289}
290
291#[allow(clippy::module_name_repetitions)]
293pub fn _alert_success_impl(message: &str) {
294 _try_slog_info(&format!("â
{}", message));
295 eprintln!("â
{}", message);
296}
297
298#[allow(clippy::module_name_repetitions)]
300pub fn _alert_debug_impl(message: &str) {
301 _try_slog_debug(message);
302 eprintln!("đ {}", message);
303}
304
305#[allow(clippy::module_name_repetitions)]
307pub fn _alert_custom_impl(severity: &str, message: &str, stop: Option<&str>, fix: Option<&str>) {
308 if let (Some(stop_msg), Some(fix_msg)) = (stop, fix) {
309 _try_slog_warn(&format!(
310 "{} {}\n {} {}\n đĄ FIX: {}",
311 severity, message, severity, stop_msg, fix_msg
312 ));
313 eprintln!(
314 "{} {}\n {} {}\n đĄ FIX: {}",
315 severity, message, severity, stop_msg, fix_msg
316 );
317 } else {
318 _try_slog_info(&format!("{} {}", severity, message));
319 eprintln!("{} {}", severity, message);
320 }
321}
322
323fn _try_slog_error(msg: &str) {
329 let _ = std::panic::catch_unwind(|| {
332 let logger = slog_scope::logger();
333 slog::error!(logger, "{}", msg);
334 });
335}
336
337fn _try_slog_warn(msg: &str) {
338 let _ = std::panic::catch_unwind(|| {
339 let logger = slog_scope::logger();
340 slog::warn!(logger, "{}", msg);
341 });
342}
343
344fn _try_slog_info(msg: &str) {
345 let _ = std::panic::catch_unwind(|| {
346 let logger = slog_scope::logger();
347 slog::info!(logger, "{}", msg);
348 });
349}
350
351fn _try_slog_debug(msg: &str) {
352 let _ = std::panic::catch_unwind(|| {
353 let logger = slog_scope::logger();
354 slog::debug!(logger, "{}", msg);
355 });
356}
357
358pub fn write_alert<W: Write>(
386 writer: &mut W, severity: &str, message: &str, stop: Option<&str>, fix: Option<&str>,
387) -> io::Result<()> {
388 if let (Some(stop_msg), Some(fix_msg)) = (stop, fix) {
389 writeln!(
390 writer,
391 "{severity} {message}\n {severity} {stop_msg}\n đĄ FIX: {fix_msg}"
392 )?;
393 } else if let Some(stop_msg) = stop {
394 writeln!(writer, "{severity} {message}\n {severity} {stop_msg}")?;
395 } else {
396 writeln!(writer, "{severity} {message}")?;
397 }
398 Ok(())
399}
400
401#[cfg(test)]
402#[allow(clippy::panic)] mod tests {
404 use super::*;
405
406 #[test]
407 fn test_alert_critical() {
408 alert_critical!("Test critical error");
410
411 alert_critical!("Test critical error", "Test fix");
413
414 alert_critical!("Test critical error", "Test fix", "Action 1", "Action 2");
416 }
417
418 #[test]
419 fn test_alert_warning() {
420 alert_warning!("Test warning");
422
423 alert_warning!("Test warning", "Test fix");
425
426 alert_warning!(
428 "Test warning: {} - Actions: {}, {}",
429 "Test fix",
430 "Action 1",
431 "Action 2"
432 );
433 }
434
435 #[test]
436 fn test_alert_info() {
437 alert_info!("Test info");
439
440 alert_info!("Test info: {}, {}", "Detail 1", "Detail 2");
442 }
443
444 #[test]
445 fn test_alert_success() {
446 alert_success!("Test success");
448
449 alert_success!("Test success: {}, {}", "Detail 1", "Detail 2");
451 }
452
453 #[test]
454 fn test_alert_debug() {
455 alert_debug!("Test debug");
457
458 alert_debug!("Test debug: {}", "value");
460 }
461
462 #[test]
463 fn test_alert_custom() {
464 alert!("đ¨", "Custom critical");
466
467 alert!(
469 "đ¨",
470 "Custom critical",
471 "STOP: Cannot proceed",
472 "FIX: Resolve issue"
473 );
474
475 alert!(
477 "đ¨",
478 "Custom critical",
479 "STOP: Cannot proceed",
480 "FIX: Resolve issue",
481 "Action 1",
482 "Action 2"
483 );
484 }
485
486 #[test]
487 fn test_write_alert() {
488 let mut buffer = Vec::new();
489
490 write_alert(&mut buffer, "đ¨", "Test error", None, None).unwrap();
492 let output = String::from_utf8_lossy(&buffer);
493 assert!(output.contains("đ¨ Test error"));
494
495 buffer.clear();
497 write_alert(
498 &mut buffer,
499 "đ¨",
500 "Test error",
501 Some("STOP: Cannot proceed"),
502 None,
503 )
504 .unwrap();
505 let output = String::from_utf8_lossy(&buffer);
506 assert!(output.contains("đ¨ Test error"));
507 assert!(output.contains("STOP: Cannot proceed"));
508
509 buffer.clear();
511 write_alert(
512 &mut buffer,
513 "đ¨",
514 "Test error",
515 Some("STOP: Cannot proceed"),
516 Some("FIX: Resolve issue"),
517 )
518 .unwrap();
519 let output = String::from_utf8_lossy(&buffer);
520 assert!(output.contains("đ¨ Test error"));
521 assert!(output.contains("STOP: Cannot proceed"));
522 assert!(output.contains("FIX: Resolve issue"));
523 }
524}