use anyhow::Error;
use console::{style, Term};
use crate::config::Config;
use crate::python_spy::PythonSpy;
use crate::stack_trace::StackTrace;
use remoteprocess::Pid;
pub fn print_traces(pid: Pid, config: &Config, parent: Option<Pid>) -> Result<(), Error> {
let mut process = PythonSpy::new(pid, config)?;
if config.dump_json {
let traces = process.get_stack_traces()?;
println!("{}", serde_json::to_string_pretty(&traces)?);
return Ok(());
}
println!(
"Process {}: {}",
style(process.pid).bold().yellow(),
process.process.cmdline()?.join(" ")
);
println!(
"Python v{} ({})",
style(&process.version).bold(),
style(process.process.exe()?).dim()
);
if let Some(parentpid) = parent {
let parentprocess = remoteprocess::Process::new(parentpid)?;
println!(
"Parent Process {}: {}",
style(parentpid).bold().yellow(),
parentprocess.cmdline()?.join(" ")
);
}
println!();
let traces = process.get_stack_traces()?;
for trace in traces.iter().rev() {
print_trace(trace, true);
if config.subprocesses {
for (childpid, parentpid) in process
.process
.child_processes()
.expect("failed to get subprocesses")
{
let term = Term::stdout();
let (_, width) = term.size();
println!("\n{}", &style("-".repeat(width as usize)).dim());
if parentpid == pid {
print_traces(childpid, config, Some(parentpid))?;
}
}
}
}
Ok(())
}
pub fn print_trace(trace: &StackTrace, include_activity: bool) {
let thread_id = trace.format_threadid();
let status = if include_activity {
format!(" ({})", trace.status_str())
} else if trace.owns_gil {
" (gil)".to_owned()
} else {
"".to_owned()
};
match trace.thread_name.as_ref() {
Some(name) => {
println!(
"Thread {}{}: \"{}\"",
style(thread_id).bold().yellow(),
status,
name
);
}
None => {
println!("Thread {}{}", style(thread_id).bold().yellow(), status);
}
};
for frame in &trace.frames {
let filename = match &frame.short_filename {
Some(f) => f,
None => &frame.filename,
};
if frame.line != 0 {
println!(
" {} ({}:{})",
style(&frame.name).green(),
style(&filename).cyan(),
style(frame.line).dim()
);
} else {
println!(
" {} ({})",
style(&frame.name).green(),
style(&filename).cyan()
);
}
if let Some(locals) = &frame.locals {
let mut shown_args = false;
let mut shown_locals = false;
for local in locals {
if local.arg && !shown_args {
println!(" {}", style("Arguments:").dim());
shown_args = true;
} else if !local.arg && !shown_locals {
println!(" {}", style("Locals:").dim());
shown_locals = true;
}
let repr = local.repr.as_deref().unwrap_or("?");
println!(" {}: {}", local.name, repr);
}
}
}
}