1- use self :: system:: System ;
21use linkerd_metrics:: { metrics, FmtMetrics , Gauge } ;
32use std:: fmt;
43use std:: sync:: Arc ;
54use std:: time:: { SystemTime , UNIX_EPOCH } ;
6- use tracing:: debug;
75
86metrics ! {
97 process_start_time_seconds: Gauge {
108 "Time that the process started (in seconds since the UNIX epoch)"
119 }
1210}
1311
14- #[ derive( Clone , Debug , Default ) ]
12+ #[ derive( Clone , Debug ) ]
1513pub struct Report {
1614 start_time : Arc < Gauge > ,
17- system : Option < System > ,
15+
16+ #[ cfg( target_os = "linux" ) ]
17+ system : linux:: System ,
1818}
1919
2020impl Report {
@@ -24,16 +24,13 @@ impl Report {
2424 . expect ( "process start time" )
2525 . as_secs ( ) ;
2626
27- let system = match System :: new ( ) {
28- Ok ( s) => Some ( s) ,
29- Err ( err) => {
30- debug ! ( "failed to load system stats: {}" , err) ;
31- None
32- }
33- } ;
27+ #[ cfg( not( target_os = "linux" ) ) ]
28+ info ! ( "System-level metrics are only supported on Linux" ) ;
3429 Self {
3530 start_time : Arc :: new ( t0. into ( ) ) ,
36- system,
31+
32+ #[ cfg( target_os = "linux" ) ]
33+ system : linux:: System :: new ( ) ,
3734 }
3835 }
3936}
@@ -43,22 +40,19 @@ impl FmtMetrics for Report {
4340 process_start_time_seconds. fmt_help ( f) ?;
4441 process_start_time_seconds. fmt_metric ( f, self . start_time . as_ref ( ) ) ?;
4542
46- if let Some ( ref sys) = self . system {
47- sys. fmt_metrics ( f) ?;
48- }
43+ #[ cfg( target_os = "linux" ) ]
44+ self . system . fmt_metrics ( f) ?;
4945
5046 Ok ( ( ) )
5147 }
5248}
5349
5450#[ cfg( target_os = "linux" ) ]
55- mod system {
56- use libc:: { self , pid_t} ;
51+ mod linux {
5752 use linkerd_metrics:: { metrics, Counter , FmtMetrics , Gauge , MillisAsSeconds } ;
58- use procinfo :: pid ;
53+ use linkerd_system as sys ;
5954 use std:: fmt;
60- use std:: { fs, io} ;
61- use tracing:: { error, warn} ;
55+ use tracing:: warn;
6256
6357 metrics ! {
6458 process_cpu_seconds_total: Counter <MillisAsSeconds > {
@@ -74,131 +68,86 @@ mod system {
7468 }
7569 }
7670
77- #[ derive( Clone , Debug ) ]
71+ #[ derive( Clone , Debug , Default ) ]
7872 pub ( super ) struct System {
79- page_size : u64 ,
80- ms_per_tick : u64 ,
73+ page_size : Option < u64 > ,
74+ ms_per_tick : Option < u64 > ,
8175 }
8276
8377 impl System {
84- pub fn new ( ) -> io:: Result < Self > {
85- let page_size = Self :: sysconf ( libc:: _SC_PAGESIZE, "page size" ) ?;
86-
87- // On Linux, CLK_TCK is ~always `100`, so pure integer division
88- // works. This is probably not suitable if we encounter other
89- // values.
90- let clock_ticks_per_sec = Self :: sysconf ( libc:: _SC_CLK_TCK, "clock ticks per second" ) ?;
91- let ms_per_tick = 1_000 / clock_ticks_per_sec;
92- if clock_ticks_per_sec != 100 {
93- warn ! (
94- clock_ticks_per_sec,
95- ms_per_tick, "Unexpected value; process_cpu_seconds_total may be inaccurate."
96- ) ;
97- }
98-
99- Ok ( Self {
100- page_size,
101- ms_per_tick,
102- } )
103- }
104-
105- fn open_fds ( pid : pid_t ) -> io:: Result < Gauge > {
106- let mut open = 0 ;
107- for f in fs:: read_dir ( format ! ( "/proc/{}/fd" , pid) ) ? {
108- if !f?. file_type ( ) ?. is_dir ( ) {
109- open += 1 ;
78+ pub fn new ( ) -> Self {
79+ let page_size = match sys:: page_size ( ) {
80+ Ok ( ps) => Some ( ps) ,
81+ Err ( err) => {
82+ warn ! ( "Failed to load page size: {}" , err) ;
83+ None
11084 }
111- }
112- Ok ( Gauge :: from ( open) )
113- }
114-
115- fn max_fds ( ) -> io:: Result < Option < Gauge > > {
116- let limit = pid:: limits_self ( ) ?. max_open_files ;
117- let max_fds = limit. soft . or ( limit. hard ) . map ( |max| Gauge :: from ( max as u64 ) ) ;
118- Ok ( max_fds)
119- }
120-
121- fn sysconf ( num : libc:: c_int , name : & ' static str ) -> Result < u64 , io:: Error > {
122- match unsafe { libc:: sysconf ( num) } {
123- e if e <= 0 => {
124- let error = io:: Error :: last_os_error ( ) ;
125- error ! ( "error getting {}: {:?}" , name, error) ;
126- Err ( error)
85+ } ;
86+ let ms_per_tick = match sys:: ms_per_tick ( ) {
87+ Ok ( mpt) => Some ( mpt) ,
88+ Err ( err) => {
89+ warn ! ( "Failed to load cpu clock speed: {}" , err) ;
90+ None
12791 }
128- val => Ok ( val as u64 ) ,
92+ } ;
93+ Self {
94+ page_size,
95+ ms_per_tick,
12996 }
13097 }
13198 }
13299
133100 impl FmtMetrics for System {
134101 fn fmt_metrics ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
135- // XXX potentially blocking call
136- let stat = match pid:: stat_self ( ) {
102+ let stat = match sys:: blocking_stat ( ) {
137103 Ok ( stat) => stat,
138104 Err ( err) => {
139105 warn ! ( "failed to read process stats: {}" , err) ;
140106 return Ok ( ( ) ) ;
141107 }
142108 } ;
143109
144- let clock_ticks = stat. utime as u64 + stat. stime as u64 ;
145- let cpu_ms = clock_ticks * self . ms_per_tick ;
146- process_cpu_seconds_total. fmt_help ( f) ?;
147- process_cpu_seconds_total. fmt_metric ( f, & Counter :: from ( cpu_ms) ) ?;
110+ if let Some ( mpt) = self . ms_per_tick {
111+ let clock_ticks = stat. utime as u64 + stat. stime as u64 ;
112+ let cpu_ms = clock_ticks * mpt;
113+ process_cpu_seconds_total. fmt_help ( f) ?;
114+ process_cpu_seconds_total. fmt_metric ( f, & Counter :: from ( cpu_ms) ) ?;
115+ } else {
116+ warn ! ( "Could not determine process_cpu_seconds_total" ) ;
117+ }
148118
149119 process_virtual_memory_bytes. fmt_help ( f) ?;
150120 process_virtual_memory_bytes. fmt_metric ( f, & Gauge :: from ( stat. vsize as u64 ) ) ?;
151121
152- process_resident_memory_bytes. fmt_help ( f) ?;
153- process_resident_memory_bytes
154- . fmt_metric ( f, & Gauge :: from ( stat. rss as u64 * self . page_size ) ) ?;
122+ if let Some ( ps) = self . page_size {
123+ process_resident_memory_bytes. fmt_help ( f) ?;
124+ process_resident_memory_bytes. fmt_metric ( f, & Gauge :: from ( stat. rss as u64 * ps) ) ?;
125+ } else {
126+ warn ! ( "Could not determine process_resident_memory_bytes" ) ;
127+ }
155128
156- match Self :: open_fds ( stat. pid ) {
129+ match sys :: open_fds ( stat. pid ) {
157130 Ok ( open_fds) => {
158131 process_open_fds. fmt_help ( f) ?;
159- process_open_fds. fmt_metric ( f, & open_fds) ?;
132+ process_open_fds. fmt_metric ( f, & open_fds. into ( ) ) ?;
160133 }
161134 Err ( err) => {
162- warn ! ( "could not determine process_open_fds: {}" , err) ;
135+ warn ! ( "Could not determine process_open_fds: {}" , err) ;
163136 }
164137 }
165138
166- match Self :: max_fds ( ) {
139+ match sys :: max_fds ( ) {
167140 Ok ( None ) => { }
168- Ok ( Some ( ref max_fds) ) => {
141+ Ok ( Some ( max_fds) ) => {
169142 process_max_fds. fmt_help ( f) ?;
170- process_max_fds. fmt_metric ( f, max_fds) ?;
143+ process_max_fds. fmt_metric ( f, & max_fds. into ( ) ) ?;
171144 }
172145 Err ( err) => {
173- warn ! ( "could not determine process_max_fds: {}" , err) ;
146+ warn ! ( "Could not determine process_max_fds: {}" , err) ;
174147 }
175148 }
176149
177150 Ok ( ( ) )
178151 }
179152 }
180153}
181-
182- #[ cfg( not( target_os = "linux" ) ) ]
183- mod system {
184- use crate :: metrics:: FmtMetrics ;
185- use std:: { fmt, io} ;
186-
187- #[ derive( Clone , Debug ) ]
188- pub ( super ) struct System { }
189-
190- impl System {
191- pub fn new ( ) -> io:: Result < Self > {
192- Err ( io:: Error :: new (
193- io:: ErrorKind :: Other ,
194- "procinfo not supported on this operating system" ,
195- ) )
196- }
197- }
198-
199- impl FmtMetrics for System {
200- fn fmt_metrics ( & self , _: & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
201- Ok ( ( ) )
202- }
203- }
204- }
0 commit comments