@@ -6,7 +6,7 @@ use std::{collections::VecDeque, io};
66use nix:: errno:: Errno ;
77use procfs:: process:: Process ;
88use rustc_hash:: FxHashSet ;
9- use tracing:: { debug, error} ;
9+ use tracing:: { debug, error, info } ;
1010
1111#[ derive( thiserror:: Error , Debug ) ]
1212/// Errors produced by functions in this module
@@ -44,61 +44,82 @@ impl Sampler {
4444 // Every sample run we collect all the child processes rooted at the
4545 // parent. As noted by the procfs documentation is this done by
4646 // dereferencing the `/proc/<pid>/root` symlink.
47+ debug ! (
48+ "Polling procfs for child processes: {pid}" ,
49+ pid = self . parent. pid( )
50+ ) ;
4751 let mut pids: FxHashSet < i32 > = FxHashSet :: default ( ) ;
4852 {
4953 let mut processes: VecDeque < Process > = VecDeque :: with_capacity ( 16 ) ; // an arbitrary smallish number
50- processes. push_back ( Process :: new ( self . parent . pid ( ) ) ?) ;
51- while let Some ( process) = processes. pop_back ( ) {
52- // Search for child processes. This is done by querying for every
53- // thread of `process` and inspecting each child of the thread. Note
54- // that processes on linux are those threads that have their group
55- // id equal to their pid. It's also possible for a pid to list
56- // itself as a child so we reference the pid hashset above to avoid
57- // infinite loops.
58- if let Ok ( tasks) = process. tasks ( ) {
59- for task in tasks. flatten ( ) {
60- if let Ok ( mut children) = task. children ( ) {
61- for child in children
62- . drain ( ..)
63- . filter_map ( |c| Process :: new ( c as i32 ) . ok ( ) )
64- {
65- let pid = child. pid ( ) ;
66- if !pids. contains ( & pid) {
67- // We have not seen this process and do need to
68- // record it for child scanning and sampling if
69- // it proves to be a process.
70- processes. push_back ( child) ;
71- pids. insert ( pid) ;
54+ match Process :: new ( self . parent . pid ( ) ) {
55+ Ok ( parent) => {
56+ pids. insert ( parent. pid ( ) ) ;
57+ processes. push_back ( parent) ;
58+ while let Some ( process) = processes. pop_back ( ) {
59+ // Search for child processes. This is done by querying for every
60+ // thread of `process` and inspecting each child of the thread. Note
61+ // that processes on linux are those threads that have their group
62+ // id equal to their pid. It's also possible for a pid to list
63+ // itself as a child so we reference the pid hashset above to avoid
64+ // infinite loops.
65+ if let Ok ( tasks) = process. tasks ( ) {
66+ for task in tasks. flatten ( ) {
67+ if let Ok ( mut children) = task. children ( ) {
68+ for child in children
69+ . drain ( ..)
70+ . filter_map ( |c| Process :: new ( c as i32 ) . ok ( ) )
71+ {
72+ let pid = child. pid ( ) ;
73+ if !pids. contains ( & pid) {
74+ // We have not seen this process and do need to
75+ // record it for child scanning and sampling if
76+ // it proves to be a process.
77+ processes. push_back ( child) ;
78+ pids. insert ( pid) ;
79+ }
80+ }
7281 }
7382 }
7483 }
7584 }
7685 }
86+ Err ( err) => {
87+ error ! (
88+ "Unable to read parent process {pid}: {err}" ,
89+ pid = self . parent. pid( )
90+ ) ;
91+ }
7792 }
78- }
7993
80- // Now iterate the pids and collect the unique names of the cgroups associated.
81- let mut cgroups = FxHashSet :: default ( ) ;
82- for pid in pids {
83- match v2:: get_path ( pid) . await {
84- Ok ( cgroup_path) => {
85- cgroups. insert ( cgroup_path) ;
86- }
87- Err ( err) => {
88- debug ! ( "Unable to get cgroup path for pid {pid}: {err}" ) ;
94+ info ! ( "Found {count} child processes" , count = pids. len( ) ) ;
95+ // Now iterate the pids and collect the unique names of the cgroups associated.
96+ let mut cgroups = FxHashSet :: default ( ) ;
97+ for pid in pids {
98+ debug ! ( "Polling cgroup for pid {pid}" , pid = pid) ;
99+ match v2:: get_path ( pid) . await {
100+ Ok ( cgroup_path) => {
101+ cgroups. insert ( cgroup_path) ;
102+ }
103+ Err ( err) => {
104+ error ! ( "Unable to get cgroup path for pid {pid}: {err}" ) ;
105+ }
89106 }
90107 }
91- }
92108
93- // Now iterate the cgroups and collect samples.
94- for cgroup_path in cgroups {
95- if let Err ( err) = v2:: poll ( & cgroup_path, & self . labels ) . await {
96- error ! (
97- "Unable to poll cgroup metrics for {path}: {err}" ,
109+ // Now iterate the cgroups and collect samples.
110+ for cgroup_path in cgroups {
111+ info ! (
112+ "Polling cgroup metrics for {path}" ,
98113 path = cgroup_path. to_string_lossy( )
99114 ) ;
115+ if let Err ( err) = v2:: poll ( & cgroup_path, & self . labels ) . await {
116+ error ! (
117+ "Unable to poll cgroup metrics for {path}: {err}" ,
118+ path = cgroup_path. to_string_lossy( )
119+ ) ;
120+ }
100121 }
122+ Ok ( ( ) )
101123 }
102- Ok ( ( ) )
103124 }
104125}
0 commit comments