use backtrace::Backtrace;
// level
// 0: 获取完整的调用链路
// 1: 获取当前函数名
// 2: 获取caller
// 3: 获取caller.caller
// 以此类推...
fn get_call_chain(level: usize) -> Option<String> {
let mut frame_line_start: usize = 0;
let mut frame_line_stop: usize = 0;
let mut project_name: String = String::new();
let mut items = vec![];
let (trace, curr_file, curr_line) = (Backtrace::new(), file!(), line!());
// 计算得出有效的 frame_line 范围: start 和 stop.
for (frame_index, frame) in trace.frames().iter().enumerate() {
// 匹配到当前函数的位置
for symbol in frame.symbols() {
let is_filename_match = match symbol.filename() {
Some(filename) => filename.ends_with(curr_file),
None => false,
};
let is_lineno_match = symbol.lineno() == Some(curr_line);
if is_filename_match && is_lineno_match {
frame_line_start = frame_index;
frame_line_stop = frame_index;
let symbol_name = symbol.name().unwrap().to_string();
project_name = symbol_name.split("::").next().unwrap().to_string();
}
}
let is_not_match = frame_line_stop == 0;
let is_not_continue = frame_index != (frame_line_stop + 1);
if is_not_match || is_not_continue {
continue;
}
// 如果连续的行持续包含project_name, 那么就持续扩大遍历范围.
for symbol in frame.symbols() {
if symbol
.name()
.unwrap()
.as_str()
.unwrap()
.starts_with(&project_name)
{
frame_line_stop += 1;
}
}
}
// 没有匹配到有效函数
if frame_line_start == 0 {
return None;
}
let stop = match level {
0 => frame_line_stop + 1,
_ => frame_line_start + 1 + level,
};
// stop边界范围无效
if stop >= trace.frames().len() {
return None;
}
// 根据 start 和 stop 提取完整的调用链路.
for i in (frame_line_start + 1)..stop {
let symbol = &trace.frames()[i].symbols()[0];
let filename_str = symbol.filename().unwrap().to_string_lossy();
let spliter = format!("{project_name}\\src\\");
let filename = filename_str.split(&spliter).last().unwrap();
items.push(format!(
"{spliter}{filename}:{}:L{}",
symbol.name().unwrap(),
symbol.lineno().unwrap()
));
}
match level {
0 => {
items.reverse();
Some(items.join("\n"))
}
i => Some(items[i - 1].to_string()),
}
}
fn foo() {
println!("current: {}\n", get_call_chain(1).unwrap()); // 获取当前函数名
println!("caller: {}\n", get_call_chain(2).unwrap()); // 获取caller
println!("caller.caller: {}\n", get_call_chain(3).unwrap()); // 获取caller.caller
println!("caller.caller.caller: {}\n", get_call_chain(4).unwrap()); // 获取caller.caller.caller
println!("full_chain: \n{}\n", get_call_chain(0).unwrap()); // 获取完整的调用链
}
fn bar() {
foo();
}
fn main() {
bar();
}