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 ::tracing::event!(::tracing::Level::INFO, account_id = $ctx.get_id(), "{}", &formatted);
18 $ctx.emit_event($crate::EventType::Info(full));
19 }};
20}
21
22pub(crate) use info;
23
24#[macro_use]
26mod warn_macro_mod {
27 macro_rules! warn_macro {
28 ($ctx:expr, $msg:expr) => {
29 warn_macro!($ctx, $msg,)
30 };
31 ($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
32 let formatted = format!($msg, $($args),*);
33 let full = format!("{file}:{line}: {msg}",
34 file = file!(),
35 line = line!(),
36 msg = &formatted);
37 ::tracing::event!(::tracing::Level::WARN, account_id = $ctx.get_id(), "{}", &formatted);
38 $ctx.emit_event($crate::EventType::Warning(full));
39 }};
40 }
41
42 pub(crate) use warn_macro;
43}
44
45pub(crate) use warn_macro_mod::warn_macro as warn;
46
47macro_rules! error {
48 ($ctx:expr, $msg:expr) => {
49 error!($ctx, $msg,)
50 };
51 ($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
52 let formatted = format!($msg, $($args),*);
53 ::tracing::event!(::tracing::Level::ERROR, account_id = $ctx.get_id(), "{}", &formatted);
54 $ctx.set_last_error(&formatted);
55 $ctx.emit_event($crate::EventType::Error(formatted));
56 }};
57}
58
59pub(crate) use error;
60
61impl Context {
62 pub fn set_last_error(&self, error: &str) {
65 let mut last_error = self.last_error.write();
66 *last_error = error.to_string();
67 }
68
69 pub fn get_last_error(&self) -> String {
71 let last_error = &*self.last_error.read();
72 last_error.clone()
73 }
74
75 pub fn set_migration_error(&self, error: &str) {
76 let mut migration_error = self.migration_error.write();
77 *migration_error = Some(error.to_string());
78 }
79
80 pub fn get_migration_error(&self) -> Option<String> {
81 let migration_error = &*self.migration_error.read();
82 migration_error.clone()
83 }
84}
85
86pub trait LogExt<T, E>
87where
88 Self: std::marker::Sized,
89{
90 #[track_caller]
101 fn log_err(self, context: &Context) -> Result<T, E>;
102}
103
104impl<T, E: std::fmt::Display> LogExt<T, E> for Result<T, E> {
105 #[track_caller]
106 fn log_err(self, context: &Context) -> Result<T, E> {
107 if let Err(e) = &self {
108 let location = std::panic::Location::caller();
109
110 let full = format!(
112 "{file}:{line}: {e:#}",
113 file = location.file(),
114 line = location.line(),
115 e = e
116 );
117 tracing::event!(
120 ::tracing::Level::WARN,
121 account_id = context.get_id(),
122 "{}",
123 &full
124 );
125 context.emit_event(crate::EventType::Warning(full));
126 };
127 self
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 use anyhow::Result;
136
137 use crate::test_utils::TestContext;
138
139 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
140 async fn test_get_last_error() -> Result<()> {
141 let t = TestContext::new().await;
142
143 assert_eq!(t.get_last_error(), "");
144
145 error!(t, "foo-error");
146 assert_eq!(t.get_last_error(), "foo-error");
147
148 warn!(t, "foo-warning");
149 assert_eq!(t.get_last_error(), "foo-error");
150
151 info!(t, "foo-info");
152 assert_eq!(t.get_last_error(), "foo-error");
153
154 error!(t, "bar-error");
155 error!(t, "baz-error");
156 assert_eq!(t.get_last_error(), "baz-error");
157
158 Ok(())
159 }
160}