|
1 |
| -from typing import NamedTuple |
2 |
| -from typing import Optional |
3 |
| - |
4 | 1 | try:
|
5 | 2 | import psutil
|
6 | 3 | except ImportError:
|
7 | 4 | psutil = None
|
8 | 5 |
|
9 |
| - |
10 |
| -class MemoryMetrics(NamedTuple): |
11 |
| - rss: int |
12 |
| - virtual_memory: int |
13 |
| - |
14 |
| - |
15 |
| -class CPUMetrics(NamedTuple): |
16 |
| - cpu_percent: float |
17 |
| - cpu_count: int |
18 |
| - |
19 |
| - |
20 |
| -def per_process_metric(metric_name, metric_kwargs={}, metric_attribute=None): |
21 |
| - if psutil is None: |
22 |
| - return None |
23 |
| - else: |
24 |
| - current_process = psutil.Process() |
25 |
| - all_processes = [current_process] + current_process.children(recursive=True) |
26 |
| - |
27 |
| - def get_per_process_metric( |
28 |
| - process, metric_name, metric_kwargs, metric_attribute=None |
29 |
| - ): |
30 |
| - try: |
31 |
| - metric_value = getattr(process, metric_name)(**metric_kwargs) |
32 |
| - if metric_attribute is not None: |
33 |
| - return getattr(metric_value, metric_attribute) |
| 6 | +from notebook.notebookapp import NotebookApp |
| 7 | + |
| 8 | + |
| 9 | +class PSUtilMetricsLoader: |
| 10 | + def __init__(self, nbapp: NotebookApp): |
| 11 | + self.config = nbapp.web_app.settings["nbresuse_display_config"] |
| 12 | + self.nbapp = nbapp |
| 13 | + |
| 14 | + def process_metric(self, name, kwargs={}, attribute=None): |
| 15 | + if psutil is None: |
| 16 | + return None |
| 17 | + else: |
| 18 | + current_process = psutil.Process() |
| 19 | + all_processes = [current_process] + current_process.children(recursive=True) |
| 20 | + |
| 21 | + def get_process_metric(process, name, kwargs, attribute=None): |
| 22 | + try: |
| 23 | + # psutil.Process methods will either return... |
| 24 | + metric_value = getattr(process, name)(**kwargs) |
| 25 | + if attribute is not None: # ... a named tuple |
| 26 | + return getattr(metric_value, attribute) |
| 27 | + else: # ... or a number |
| 28 | + return metric_value |
| 29 | + # Avoid littering logs with stack traces |
| 30 | + # complaining about dead processes |
| 31 | + except BaseException: |
| 32 | + return 0 |
| 33 | + |
| 34 | + process_metric_value = lambda process: get_process_metric( |
| 35 | + process, name, kwargs, attribute |
| 36 | + ) |
| 37 | + |
| 38 | + return sum([process_metric_value(process) for process in all_processes]) |
| 39 | + |
| 40 | + def system_metric(self, name, kwargs={}, attribute=None): |
| 41 | + if psutil is None: |
| 42 | + return None |
| 43 | + else: |
| 44 | + # psutil functions will either return... |
| 45 | + metric_value = getattr(psutil, name)(**kwargs) |
| 46 | + if attribute is not None: # ... a named tuple |
| 47 | + return getattr(metric_value, attribute) |
| 48 | + else: # ... or a number |
34 | 49 | return metric_value
|
35 |
| - # Avoid littering logs with stack traces |
36 |
| - # complaining about dead processes |
37 |
| - except BaseException: |
38 |
| - return 0 |
39 |
| - |
40 |
| - per_process_metric_value = lambda process: get_per_process_metric( |
41 |
| - process, metric_name, metric_kwargs, metric_attribute |
42 |
| - ) |
43 |
| - |
44 |
| - return sum([per_process_metric_value(process) for process in all_processes]) |
45 | 50 |
|
| 51 | + def get_metric_values(self, metrics, metric_type): |
| 52 | + metric_types = {"process": self.process_metric, "system": self.system_metric} |
| 53 | + metric_value = metric_types[metric_type] # Switch statement |
46 | 54 |
|
47 |
| -def system_metric(metric_name, metric_kwargs={}, metric_attribute=None): |
48 |
| - if psutil is None: |
49 |
| - return None |
50 |
| - else: |
51 |
| - metric_value = getattr(psutil, metric_name)(**metric_kwargs) |
52 |
| - if metric_attribute is not None: |
53 |
| - return getattr(metric_value, metric_attribute) |
54 |
| - return metric_attribute |
| 55 | + metric_values = {} |
| 56 | + for metric in metrics: |
| 57 | + name = metric["name"] |
| 58 | + if metric.get("attribute", False): |
| 59 | + name += "_" + metric.get("attribute") |
| 60 | + metric_values.update({name: metric_value(**metric)}) |
| 61 | + return metric_values |
55 | 62 |
|
| 63 | + def metrics(self, process_metrics, system_metrics): |
56 | 64 |
|
57 |
| -def memory_metrics() -> Optional[MemoryMetrics]: |
| 65 | + metric_values = self.get_metric_values(process_metrics, "process") |
| 66 | + metric_values.update(self.get_metric_values(system_metrics, "system")) |
58 | 67 |
|
59 |
| - rss = {"metric_name": "memory_info", "metric_attribute": "rss"} |
60 |
| - rss_value = per_process_metric(**rss) |
| 68 | + if any(value is None for value in metric_values.values()): |
| 69 | + return None |
61 | 70 |
|
62 |
| - virtual_memory = {"metric_name": "virtual_memory", "metric_attribute": "total"} |
63 |
| - virtual_memory_value = system_metric(**virtual_memory) |
| 71 | + return metric_values |
64 | 72 |
|
65 |
| - memory_metric_values = {"rss": rss_value, "virtual_memory": virtual_memory_value} |
66 |
| - |
67 |
| - if any(value is None for value in memory_metric_values.values()): |
68 |
| - return None |
69 |
| - |
70 |
| - return MemoryMetrics(**memory_metric_values) |
71 |
| - |
72 |
| - |
73 |
| -def cpu_metrics() -> Optional[CPUMetrics]: |
74 |
| - |
75 |
| - cpu_percent = {"metric_name": "cpu_percent", "metric_kwargs": {"interval": 0.05}} |
76 |
| - cpu_percent_value = per_process_metric(**cpu_percent) |
77 |
| - |
78 |
| - cpu_count = {"metric_name": "cpu_count"} |
79 |
| - cpu_count_value = system_metric(**cpu_count) |
80 |
| - |
81 |
| - cpu_metric_values = {"cpu_percent": cpu_percent_value, "cpu_count": cpu_count_value} |
82 |
| - |
83 |
| - if any(value is None for value in cpu_metric_values.values()): |
84 |
| - return None |
| 73 | + def memory_metrics(self): |
| 74 | + return self.metrics( |
| 75 | + self.config.process_memory_metrics, self.config.system_memory_metrics |
| 76 | + ) |
85 | 77 |
|
86 |
| - return CPUMetrics(**cpu_metric_values) |
| 78 | + def cpu_metrics(self): |
| 79 | + return self.metrics( |
| 80 | + self.config.process_cpu_metrics, self.config.system_cpu_metrics |
| 81 | + ) |
0 commit comments