1#[cfg(feature = "backtrace")]
2#[inline]
3pub fn get_caller_data() -> Option<String> {
4 let stack_trace = backtrace::Backtrace::new();
5 let caller = stack_trace
6 .frames()
7 .iter()
8 .filter(|x| x.symbols().first().and_then(|x| x.name()).and_then(|x| x.as_str()).is_some())
9 .filter(|x| {
10 static BLACKLIST: [&str; 7] = ["backtrace::", "ruva_core::", "tokio::", "core::", "std::", "test::", "futures::"];
11 let name = x.symbols().first().and_then(|x| x.name()).and_then(|x| x.as_str()).unwrap();
12 if BLACKLIST.iter().any(|y| name.starts_with(y)) {
13 return false;
14 }
15 true
16 })
17 .map(|x| x.symbols().first().unwrap())
18 .next()
19 .cloned()?;
20
21 let module_path = caller.name().expect("caller에서 name을 기준으로 비교했기 때문에 현재는 값이 반드시 존재함");
22 let filename = caller.filename();
23 let line = caller.lineno();
24
25 let mut result = String::new();
26 result.push_str(module_path.as_str().unwrap());
27 if let Some(file_path) = filename {
28 if let Some(file_path) = file_path.to_str() {
29 result.push(' ');
30 result.push_str(file_path);
31 }
32 }
33
34 if let Some(line_no) = line {
35 result.push(':');
36 result.push_str(line_no.to_string().as_str());
37 }
38 Some(result)
39}
40
41#[macro_export]
42macro_rules! backtrace_error {
43 ($($arg:tt)*) => {
44 #[cfg(feature = "backtrace")]
45 {
46 let caller = $crate::backtrace::get_caller_data();
47 if caller.is_some() {
48 let caller = caller.unwrap();
49 tracing::error!(?caller, $($arg)*);
50 } else {
51 tracing::error!($($arg)*);
52 }
53 }
54 #[cfg(not(feature = "backtrace"))]
55 {
56 tracing::error!($($arg)*);
57 }
58 };
59}