1+ use std:: io:: Write ;
2+
13use anyhow:: { Context , Error } ;
24use console:: { style, Term } ;
35
@@ -8,64 +10,91 @@ use crate::stack_trace::StackTrace;
810use remoteprocess:: Pid ;
911
1012pub fn print_traces ( pid : Pid , config : & Config , parent : Option < Pid > ) -> Result < ( ) , Error > {
13+ let stdout = std:: io:: stdout ( ) ;
14+ let mut out = stdout. lock ( ) ;
15+ write_traces ( & mut out, pid, config, parent)
16+ }
17+
18+ pub fn write_traces < W : Write > (
19+ out : & mut W ,
20+ pid : Pid ,
21+ config : & Config ,
22+ parent : Option < Pid > ,
23+ ) -> Result < ( ) , Error > {
1124 let mut process = PythonSpy :: new ( pid, config) ?;
1225 if config. dump_json {
1326 let traces = process
1427 . get_stack_traces ( )
1528 . context ( "Failed to get stack traces" ) ?;
16- println ! ( "{}" , serde_json:: to_string_pretty( & traces) ?) ;
29+ writeln ! ( out , "{}" , serde_json:: to_string_pretty( & traces) ?) ? ;
1730 return Ok ( ( ) ) ;
1831 }
1932
20- println ! (
33+ writeln ! (
34+ out,
2135 "Process {}: {}" ,
2236 style( process. pid) . bold( ) . yellow( ) ,
2337 process. process. cmdline( ) ?. join( " " )
24- ) ;
38+ ) ? ;
2539
26- println ! (
40+ writeln ! (
41+ out,
2742 "Python v{} ({})" ,
2843 style( & process. version) . bold( ) ,
2944 style( process. process. exe( ) ?) . dim( )
30- ) ;
45+ ) ? ;
3146
3247 if let Some ( parentpid) = parent {
3348 let parentprocess = remoteprocess:: Process :: new ( parentpid) ?;
34- println ! (
49+ writeln ! (
50+ out,
3551 "Parent Process {}: {}" ,
3652 style( parentpid) . bold( ) . yellow( ) ,
3753 parentprocess. cmdline( ) ?. join( " " )
38- ) ;
54+ ) ? ;
3955 }
40- println ! ( ) ;
56+ writeln ! ( out ) ? ;
4157 let traces = process
4258 . get_stack_traces ( )
4359 . context ( "Failed to get stack traces" ) ?;
4460 for trace in traces. iter ( ) . rev ( ) {
45- print_trace ( trace, true ) ;
46- if config. subprocesses {
47- for ( childpid, parentpid) in process
48- . process
49- . child_processes ( )
50- . expect ( "failed to get subprocesses" )
51- {
52- let term = Term :: stdout ( ) ;
53- let ( _, width) = term. size ( ) ;
54-
55- println ! ( "\n {}" , & style( "-" . repeat( width as usize ) ) . dim( ) ) ;
56- // child_processes() returns the whole process tree, since we're recursing here
57- // though we could end up printing grandchild processes multiple times. Limit down
58- // to just once
59- if parentpid == pid {
60- print_traces ( childpid, config, Some ( parentpid) ) ?;
61- }
61+ write_trace ( out, trace, true ) ?;
62+ }
63+
64+ if config. subprocesses {
65+ for ( childpid, parentpid) in process
66+ . process
67+ . child_processes ( )
68+ . expect ( "failed to get subprocesses" )
69+ {
70+ let term = Term :: stdout ( ) ;
71+ let ( _, width) = term. size ( ) ;
72+
73+ writeln ! ( out, "\n {}" , & style( "-" . repeat( width as usize ) ) . dim( ) ) ?;
74+ // child_processes() returns the whole process tree, since we're recursing here
75+ // though we could end up printing grandchild processes multiple times. Limit down
76+ // to just once
77+ if parentpid == pid {
78+ write_traces ( out, childpid, config, Some ( parentpid) ) ?;
6279 }
6380 }
6481 }
6582 Ok ( ( ) )
6683}
6784
85+ #[ cfg( target_os = "linux" ) ]
6886pub fn print_trace ( trace : & StackTrace , include_activity : bool ) {
87+ let stdout = std:: io:: stdout ( ) ;
88+ let mut out = stdout. lock ( ) ;
89+ // Swallow write errors here to preserve the old println! behaviour.
90+ let _ = write_trace ( & mut out, trace, include_activity) ;
91+ }
92+
93+ pub fn write_trace < W : Write > (
94+ out : & mut W ,
95+ trace : & StackTrace ,
96+ include_activity : bool ,
97+ ) -> Result < ( ) , Error > {
6998 let thread_id = trace. format_threadid ( ) ;
7099
71100 let status = if include_activity {
@@ -78,15 +107,16 @@ pub fn print_trace(trace: &StackTrace, include_activity: bool) {
78107
79108 match trace. thread_name . as_ref ( ) {
80109 Some ( name) => {
81- println ! (
110+ writeln ! (
111+ out,
82112 "Thread {}{}: \" {}\" " ,
83113 style( thread_id) . bold( ) . yellow( ) ,
84114 status,
85115 name
86- ) ;
116+ ) ? ;
87117 }
88118 None => {
89- println ! ( "Thread {}{}" , style( thread_id) . bold( ) . yellow( ) , status) ;
119+ writeln ! ( out , "Thread {}{}" , style( thread_id) . bold( ) . yellow( ) , status) ? ;
90120 }
91121 } ;
92122
@@ -96,35 +126,38 @@ pub fn print_trace(trace: &StackTrace, include_activity: bool) {
96126 None => & frame. filename ,
97127 } ;
98128 if frame. line != 0 {
99- println ! (
129+ writeln ! (
130+ out,
100131 " {} ({}:{})" ,
101132 style( & frame. name) . green( ) ,
102133 style( & filename) . cyan( ) ,
103134 style( frame. line) . dim( )
104- ) ;
135+ ) ? ;
105136 } else {
106- println ! (
137+ writeln ! (
138+ out,
107139 " {} ({})" ,
108140 style( & frame. name) . green( ) ,
109141 style( & filename) . cyan( )
110- ) ;
142+ ) ? ;
111143 }
112144
113145 if let Some ( locals) = & frame. locals {
114146 let mut shown_args = false ;
115147 let mut shown_locals = false ;
116148 for local in locals {
117149 if local. arg && !shown_args {
118- println ! ( " {}" , style( "Arguments:" ) . dim( ) ) ;
150+ writeln ! ( out , " {}" , style( "Arguments:" ) . dim( ) ) ? ;
119151 shown_args = true ;
120152 } else if !local. arg && !shown_locals {
121- println ! ( " {}" , style( "Locals:" ) . dim( ) ) ;
153+ writeln ! ( out , " {}" , style( "Locals:" ) . dim( ) ) ? ;
122154 shown_locals = true ;
123155 }
124156
125157 let repr = local. repr . as_deref ( ) . unwrap_or ( "?" ) ;
126- println ! ( " {}: {}" , local. name, repr) ;
158+ writeln ! ( out , " {}: {}" , local. name, repr) ? ;
127159 }
128160 }
129161 }
162+ Ok ( ( ) )
130163}
0 commit comments