Skip to content

Latest commit

 

History

History
111 lines (95 loc) · 3.31 KB

06_如何获取完整的调用链.md

File metadata and controls

111 lines (95 loc) · 3.31 KB

如何获取完整的调用链

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();
}