4
4
5
5
import copy
6
6
import re
7
+ import resource
7
8
import os
8
9
import time
9
10
import threading
@@ -419,7 +420,7 @@ def generate_latest(registry=REGISTRY):
419
420
labelstr = '{{{0}}}' .format (',' .join (
420
421
['{0}="{1}"' .format (
421
422
k , v .replace ('\\ ' , r'\\' ).replace ('\n ' , r'\n' ).replace ('"' , r'\"' ))
422
- for k , v in labels .items ()]))
423
+ for k , v in sorted ( labels .items () )]))
423
424
else :
424
425
labelstr = ''
425
426
output .append ('{0}{1} {2}\n ' .format (name , labelstr , _floatToGoString (value )))
@@ -446,6 +447,82 @@ def write_to_textfile(path, registry):
446
447
os .rename (tmppath , path )
447
448
448
449
450
+
451
+ class ProcessCollector (object ):
452
+ """Collector for Standard Exports such as cpu and memory."""
453
+ def __init__ (self , namespace = '' , pid = 'self' , proc = '/proc' , registry = REGISTRY ):
454
+ self ._namespace = namespace
455
+ self ._pid = os .path .join (proc , str (pid ))
456
+ self ._proc = proc
457
+ self ._pagesize = resource .getpagesize ()
458
+ if namespace :
459
+ self ._prefix = namespace + '_process_'
460
+ else :
461
+ self ._prefix = 'process_'
462
+ self ._ticks = 100.0
463
+ try :
464
+ self ._ticks = os .sysconf ('SC_CLK_TCK' )
465
+ except (ValueError , TypeError ):
466
+ pass
467
+
468
+ self ._can_read_proc = os .access (os .path .join (self ._proc , 'stat' ), os .R_OK )
469
+ if self ._can_read_proc :
470
+ self ._btime = self ._boot_time ()
471
+ if registry :
472
+ registry .register (self )
473
+
474
+ def _boot_time (self ):
475
+ with open (os .path .join (self ._proc , 'stat' )) as stat :
476
+ for line in stat :
477
+ if line .startswith ('btime ' ):
478
+ return float (line .split ()[1 ])
479
+
480
+ def collect (self ):
481
+ if not self ._can_read_proc :
482
+ return []
483
+
484
+ result = []
485
+ try :
486
+ with open (os .path .join (self ._pid , 'stat' )) as stat :
487
+ parts = (stat .read ().split (')' )[- 1 ].split ())
488
+ vmem = Metric (self ._prefix + 'virtual_memory_bytes' , 'Virtual memory size in bytes' , 'gauge' )
489
+ vmem .add_sample (self ._prefix + 'virtual_memory_bytes' , {}, float (parts [20 ]))
490
+ rss = Metric (self ._prefix + 'resident_memory_bytes' , 'Resident memory size in bytes' , 'gauge' )
491
+ rss .add_sample (self ._prefix + 'resident_memory_bytes' , {}, float (parts [21 ]) * self ._pagesize )
492
+ start_time = Metric (self ._prefix + 'start_time_seconds' ,
493
+ 'Start time of the process since unix epoch in seconds.' , 'gauge' )
494
+ start_time_secs = float (parts [18 ]) / self ._ticks
495
+ start_time .add_sample (self ._prefix + 'start_time_seconds' ,{} , start_time_secs + self ._btime )
496
+ utime = float (parts [11 ]) / self ._ticks
497
+ stime = float (parts [12 ]) / self ._ticks
498
+ cpu = Metric (self ._prefix + 'cpu_seconds_total' ,
499
+ 'Total user and system CPU time spent in seconds.' , 'counter' )
500
+ cpu .add_sample (self ._prefix + 'cpu_seconds_total' , {}, utime + stime )
501
+ result .extend ([vmem , rss , start_time , cpu ])
502
+ except (IOError ):
503
+ pass
504
+
505
+ try :
506
+ max_fds = Metric (self ._prefix + 'max_fds' , 'Maximum number of open file descriptors.' , 'gauge' )
507
+ with open (os .path .join (self ._pid , 'limits' )) as limits :
508
+ for line in limits :
509
+ if line .startswith ('Max open file' ):
510
+ max_fds .add_sample (self ._prefix + 'max_fds' , {}, float (line .split ()[3 ]))
511
+ break
512
+ open_fds = Metric (self ._prefix + 'open_fds' , 'Number of open file descriptors.' , 'gauge' )
513
+ open_fds .add_sample (self ._prefix + 'open_fds' , {}, os .listdir (os .path .join (self ._pid , 'fd' )))
514
+ result .extend ([open_fds , max_fds ])
515
+ except IOError :
516
+ pass
517
+
518
+ return result
519
+
520
+
521
+ PROCESS_COLLECTOR = ProcessCollector (proc = '.' )
522
+ """Default ProcessCollector in default Registry REGISTRY."""
523
+
524
+
525
+
449
526
if __name__ == '__main__' :
450
527
c = Counter ('cc' , 'A counter' )
451
528
c .inc ()
0 commit comments