@@ -6,7 +6,7 @@ use std::{collections::VecDeque, io};
6
6
use nix:: errno:: Errno ;
7
7
use procfs:: process:: Process ;
8
8
use rustc_hash:: FxHashSet ;
9
- use tracing:: { debug, error} ;
9
+ use tracing:: { debug, error, info } ;
10
10
11
11
#[ derive( thiserror:: Error , Debug ) ]
12
12
/// Errors produced by functions in this module
@@ -44,61 +44,82 @@ impl Sampler {
44
44
// Every sample run we collect all the child processes rooted at the
45
45
// parent. As noted by the procfs documentation is this done by
46
46
// dereferencing the `/proc/<pid>/root` symlink.
47
+ debug ! (
48
+ "Polling procfs for child processes: {pid}" ,
49
+ pid = self . parent. pid( )
50
+ ) ;
47
51
let mut pids: FxHashSet < i32 > = FxHashSet :: default ( ) ;
48
52
{
49
53
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
+ }
72
81
}
73
82
}
74
83
}
75
84
}
76
85
}
86
+ Err ( err) => {
87
+ error ! (
88
+ "Unable to read parent process {pid}: {err}" ,
89
+ pid = self . parent. pid( )
90
+ ) ;
91
+ }
77
92
}
78
- }
79
93
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
+ }
89
106
}
90
107
}
91
- }
92
108
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}" ,
98
113
path = cgroup_path. to_string_lossy( )
99
114
) ;
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
+ }
100
121
}
122
+ Ok ( ( ) )
101
123
}
102
- Ok ( ( ) )
103
124
}
104
125
}
0 commit comments