1#![allow(missing_docs)]
4
5use crate::context::Context;
6
7macro_rules! info {
8 ($ctx:expr, $msg:expr) => {
9 info!($ctx, $msg,)
10 };
11 ($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
12 let formatted = format!($msg, $($args),*);
13 let full = format!("{file}:{line}: {msg}",
14 file = file!(),
15 line = line!(),
16 msg = &formatted);
17 $ctx.emit_event($crate::EventType::Info(full));
18 }};
19}
20
21pub(crate) use info;
22
23#[macro_use]
25mod warn_macro_mod {
26 macro_rules! warn_macro {
27 ($ctx:expr, $msg:expr) => {
28 warn_macro!($ctx, $msg,)
29 };
30 ($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
31 let formatted = format!($msg, $($args),*);
32 let full = format!("{file}:{line}: {msg}",
33 file = file!(),
34 line = line!(),
35 msg = &formatted);
36 $ctx.emit_event($crate::EventType::Warning(full));
37 }};
38 }
39
40 pub(crate) use warn_macro;
41}
42
43pub(crate) use warn_macro_mod::warn_macro as warn;
44
45macro_rules! error {
46 ($ctx:expr, $msg:expr) => {
47 error!($ctx, $msg,)
48 };
49 ($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
50 let formatted = format!($msg, $($args),*);
51 $ctx.set_last_error(&formatted);
52 $ctx.emit_event($crate::EventType::Error(formatted));
53 }};
54}
55
56pub(crate) use error;
57
58impl Context {
59 pub fn set_last_error(&self, error: &str) {
62 let mut last_error = self.last_error.write();
63 *last_error = error.to_string();
64 }
65
66 pub fn get_last_error(&self) -> String {
68 let last_error = &*self.last_error.read();
69 last_error.clone()
70 }
71
72 pub fn set_migration_error(&self, error: &str) {
73 let mut migration_error = self.migration_error.write();
74 *migration_error = Some(error.to_string());
75 }
76
77 pub fn get_migration_error(&self) -> Option<String> {
78 let migration_error = &*self.migration_error.read();
79 migration_error.clone()
80 }
81}
82
83pub trait LogExt<T, E>
84where
85 Self: std::marker::Sized,
86{
87 #[track_caller]
98 fn log_err(self, context: &Context) -> Result<T, E>;
99}
100
101impl<T, E: std::fmt::Display> LogExt<T, E> for Result<T, E> {
102 #[track_caller]
103 fn log_err(self, context: &Context) -> Result<T, E> {
104 if let Err(e) = &self {
105 let location = std::panic::Location::caller();
106
107 let full = format!(
109 "{file}:{line}: {e:#}",
110 file = location.file(),
111 line = location.line(),
112 e = e
113 );
114 context.emit_event(crate::EventType::Warning(full));
117 };
118 self
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 use anyhow::Result;
127
128 use crate::test_utils::TestContext;
129
130 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
131 async fn test_get_last_error() -> Result<()> {
132 let t = TestContext::new().await;
133
134 assert_eq!(t.get_last_error(), "");
135
136 error!(t, "foo-error");
137 assert_eq!(t.get_last_error(), "foo-error");
138
139 warn!(t, "foo-warning");
140 assert_eq!(t.get_last_error(), "foo-error");
141
142 info!(t, "foo-info");
143 assert_eq!(t.get_last_error(), "foo-error");
144
145 error!(t, "bar-error");
146 error!(t, "baz-error");
147 assert_eq!(t.get_last_error(), "baz-error");
148
149 Ok(())
150 }
151}