Skip to content

Commit efbabea

Browse files
committed
Apply code review comments, update docs.
1 parent 6d211e6 commit efbabea

File tree

6 files changed

+38
-18
lines changed

6 files changed

+38
-18
lines changed

AUTHORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ Maintainers of this repository:
55
The following individuals have contributed code to this repository
66
(listed in alphabetical order):
77

8+
* Andrea Fagan <andreafagan28@gmail.com>
89
* Brian Brazil <brian.brazil@gmail.com>

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ c.labels('get', '/').inc()
133133
c.labels('post', '/submit').inc()
134134
```
135135

136+
### Process Collector
137+
138+
The Python Client automatically exports metrics about process CPU usage, RAM,
139+
file descriptors and start time. These all have the prefix `process\_`, and
140+
are only currently available on Linux.
141+
136142
## Exporting
137143

138144
There are several options for exporting metrics.
@@ -180,4 +186,5 @@ g.set(1)
180186
write_to_textfile('/configured/textfile/path/raid.prom', registry)
181187
```
182188

183-
A separate registry is used, as the default registry may contain other metrics.
189+
A separate registry is used, as the default registry may contain other metrics
190+
such as those from the Process Collector.

prometheus_client/__init__.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,6 @@ def write_to_textfile(path, registry):
447447
os.rename(tmppath, path)
448448

449449

450-
451450
class ProcessCollector(object):
452451
"""Collector for Standard Exports such as cpu and memory."""
453452
def __init__(self, namespace='', pid='self', proc='/proc', registry=REGISTRY):
@@ -465,9 +464,12 @@ def __init__(self, namespace='', pid='self', proc='/proc', registry=REGISTRY):
465464
except (ValueError, TypeError):
466465
pass
467466

468-
self._can_read_proc = os.access(os.path.join(self._proc, 'stat'), os.R_OK)
469-
if self._can_read_proc:
467+
# This is used to test if we can access /proc.
468+
self._btime = 0
469+
try:
470470
self._btime = self._boot_time()
471+
except IOError:
472+
pass
471473
if registry:
472474
registry.register(self)
473475

@@ -478,7 +480,7 @@ def _boot_time(self):
478480
return float(line.split()[1])
479481

480482
def collect(self):
481-
if not self._can_read_proc:
483+
if not self._btime:
482484
return []
483485

484486
result = []
@@ -491,15 +493,15 @@ def collect(self):
491493
rss.add_sample(self._prefix + 'resident_memory_bytes', {}, float(parts[21]) * self._pagesize)
492494
start_time = Metric(self._prefix + 'start_time_seconds',
493495
'Start time of the process since unix epoch in seconds.', 'gauge')
494-
start_time_secs = float(parts[18]) / self._ticks
496+
start_time_secs = float(parts[19]) / self._ticks
495497
start_time.add_sample(self._prefix + 'start_time_seconds',{} , start_time_secs + self._btime)
496498
utime = float(parts[11]) / self._ticks
497499
stime = float(parts[12]) / self._ticks
498500
cpu = Metric(self._prefix + 'cpu_seconds_total',
499501
'Total user and system CPU time spent in seconds.', 'counter')
500502
cpu.add_sample(self._prefix + 'cpu_seconds_total', {}, utime + stime)
501503
result.extend([vmem, rss, start_time, cpu])
502-
except (IOError):
504+
except IOError:
503505
pass
504506

505507
try:
@@ -510,19 +512,18 @@ def collect(self):
510512
max_fds.add_sample(self._prefix + 'max_fds', {}, float(line.split()[3]))
511513
break
512514
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')))
515+
open_fds.add_sample(self._prefix + 'open_fds', {}, len(os.listdir(os.path.join(self._pid, 'fd'))))
514516
result.extend([open_fds, max_fds])
515517
except IOError:
516518
pass
517519

518520
return result
519521

520522

521-
PROCESS_COLLECTOR = ProcessCollector(proc='.')
523+
PROCESS_COLLECTOR = ProcessCollector()
522524
"""Default ProcessCollector in default Registry REGISTRY."""
523525

524526

525-
526527
if __name__ == '__main__':
527528
c = Counter('cc', 'A counter')
528529
c.inc()

tests/proc/26231/limits

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,3 @@ Max file locks unlimited unlimited locks
1313
Max pending signals 62898 62898 signals
1414
Max msgqueue size 819200 819200 bytes
1515
Max nice priority 0 0
16-
Max rMax rMax rMax rMax rMax rMax rMax rMax rMax rMax rMax rMax rMax rMax rMax mited unlimited us

tests/proc/584/stat

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
1020 ((a b ) ( c d) ) R 28378 1020 28378 34842 1020 4218880 286 0 0 0 0 0 0 0 20 0 1 0 10839175 10395648 155 18446744073709551615 4194304 4238788 140736466511168 140736466511168 140609271124624 0 0 0 0 0 0 0 17 5 0 0 0 0 0 6336016 6337300 25579520 140736466515030 140736466515061 140736466515061 140736466518002 0
2-
#!/bin/cat /proc/self/stat

tests/test_client.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,23 +280,36 @@ def test_working(self):
280280

281281
self.assertEqual(17.21, self.registry.get_sample_value('process_cpu_seconds_total'))
282282
self.assertEqual(56274944.0, self.registry.get_sample_value('process_virtual_memory_bytes'))
283-
self.assertEqual((1981.0*collector._pagesize), self.registry.get_sample_value('process_resident_memory_bytes'))
284-
self.assertEqual((0.0/collector._ticks+1418183276), self.registry.get_sample_value('process_start_time_seconds'))
283+
self.assertEqual(8114176, self.registry.get_sample_value('process_resident_memory_bytes'))
284+
self.assertEqual(1418184099.75, self.registry.get_sample_value('process_start_time_seconds'))
285285
self.assertEqual(2048.0, self.registry.get_sample_value('process_max_fds'))
286-
self.assertEqual(5.0, len(self.registry.get_sample_value('process_open_fds')))
286+
self.assertEqual(5.0, self.registry.get_sample_value('process_open_fds'))
287287
self.assertEqual(None, self.registry.get_sample_value('process_fake_namespace'))
288288

289+
def test_namespace(self):
290+
collector = ProcessCollector(proc=self.test_proc, pid=26231, registry=self.registry, namespace='n')
291+
collector._pagesize = 4096
292+
collector._ticks = 100
293+
294+
self.assertEqual(17.21, self.registry.get_sample_value('n_process_cpu_seconds_total'))
295+
self.assertEqual(56274944.0, self.registry.get_sample_value('n_process_virtual_memory_bytes'))
296+
self.assertEqual(8114176, self.registry.get_sample_value('n_process_resident_memory_bytes'))
297+
self.assertEqual(1418184099.75, self.registry.get_sample_value('n_process_start_time_seconds'))
298+
self.assertEqual(2048.0, self.registry.get_sample_value('n_process_max_fds'))
299+
self.assertEqual(5.0, self.registry.get_sample_value('n_process_open_fds'))
300+
self.assertEqual(None, self.registry.get_sample_value('process_cpu_seconds_total'))
301+
289302
def test_working_584(self):
290303
collector = ProcessCollector(proc=self.test_proc, pid=584, registry=self.registry)
291304
collector._pagesize = 4096
292305
collector._ticks = 100
293306

294307
self.assertEqual(0.0, self.registry.get_sample_value('process_cpu_seconds_total'))
295308
self.assertEqual(10395648.0, self.registry.get_sample_value('process_virtual_memory_bytes'))
296-
self.assertEqual((155.0*collector._pagesize), self.registry.get_sample_value('process_resident_memory_bytes'))
297-
self.assertEqual((0.0/collector._ticks+1418183276), self.registry.get_sample_value('process_start_time_seconds'))
309+
self.assertEqual(634880, self.registry.get_sample_value('process_resident_memory_bytes'))
310+
self.assertEqual(1418291667.75, self.registry.get_sample_value('process_start_time_seconds'))
298311
self.assertEqual(None, self.registry.get_sample_value('process_max_fds'))
299-
self.assertEqual(None, (self.registry.get_sample_value('process_open_fds')))
312+
self.assertEqual(None, self.registry.get_sample_value('process_open_fds'))
300313

301314
def test_working_fake_pid(self):
302315
collector = ProcessCollector(proc=self.test_proc, pid=123, registry=self.registry)

0 commit comments

Comments
 (0)