Skip to content

Commit

Permalink
Add a subprocesses option for the dump command (#492)
Browse files Browse the repository at this point in the history
Adds the ability to print out stack traces from subprocesses
when running the dump command, like we can already do for
the record / top commands
  • Loading branch information
benfred committed May 16, 2022
1 parent 232e3c1 commit ef380e5
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 6 deletions.
5 changes: 3 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,8 @@ impl Config {
.arg(Arg::new("json")
.short('j')
.long("json")
.help("Format output as JSON"));
.help("Format output as JSON"))
.arg(subprocesses.clone());

let completions = Command::new("completions")
.about("Generate shell completions")
Expand Down Expand Up @@ -337,11 +338,11 @@ impl Config {
});
config.gil_only = matches.occurrences_of("gil") > 0;
config.include_idle = matches.occurrences_of("idle") > 0;
config.subprocesses = matches.occurrences_of("subprocesses") > 0;
},
_ => {}
}

config.subprocesses = matches.occurrences_of("subprocesses") > 0;
config.command = subcommand.to_owned();

// options that can be shared between subcommands
Expand Down
29 changes: 26 additions & 3 deletions src/dump.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use console::style;
use console::{Term, style};
use failure::Error;

use crate::config::Config;
use crate::python_spy::PythonSpy;

use remoteprocess::Pid;

pub fn print_traces(pid: Pid, config: &Config) -> Result<(), Error> {
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()?;
Expand All @@ -18,10 +18,18 @@ pub fn print_traces(pid: Pid, config: &Config) -> Result<(), Error> {
style(process.pid).bold().yellow(),
process.process.cmdline()?.join(" "));

println!("Python v{} ({})\n",
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() {
Expand Down Expand Up @@ -60,6 +68,21 @@ pub fn print_traces(pid: Pid, config: &Config) -> Result<(), Error> {
}
}
}

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());
// child_processes() returns the whole process tree, since we're recursing here
// though we could end up printing grandchild processes multiple times. Limit down
// to just once
if parentpid == pid {
print_traces(childpid, &config, Some(parentpid))?;
}
}
}
}
Ok(())
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ fn record_samples(pid: remoteprocess::Pid, config: &Config) -> Result<(), Error>
fn run_spy_command(pid: remoteprocess::Pid, config: &config::Config) -> Result<(), Error> {
match config.command.as_ref() {
"dump" => {
dump::print_traces(pid, config)?;
dump::print_traces(pid, config, None)?;
},
"record" => {
record_samples(pid, config)?;
Expand Down

0 comments on commit ef380e5

Please sign in to comment.