1class Metric(object): 2 """Abstract base class for metrics.""" 3 def __init__(self, 4 description, 5 units=None, 6 higher_is_better=False): 7 """ 8 Initializes a Metric. 9 @param description: Description of the metric, e.g., used as label on a 10 dashboard chart 11 @param units: Units of the metric, e.g. percent, seconds, MB. 12 @param higher_is_better: Whether a higher value is considered better or 13 not. 14 """ 15 self.values = [] 16 self.description = description 17 self.units = units 18 self.higher_is_better = higher_is_better 19 20 def collect_metric(self): 21 """ 22 Collects one metric. 23 24 Implementations should add a metric value to the self.values list. 25 """ 26 raise NotImplementedError('Subclasses should override') 27 28class PeakMetric(Metric): 29 """ 30 Metric that collects the peak of another metric. 31 """ 32 def __init__(self, metric): 33 """ 34 Initializes with a Metric. 35 36 @param metric The Metric to get the peak from. 37 """ 38 super(PeakMetric, self).__init__( 39 'peak_' + metric.description, 40 units = metric.units, 41 higher_is_better = metric.higher_is_better) 42 self.metric = metric 43 44 def collect_metric(self): 45 self.values = [max(self.metric.values)] if self.metric.values else [] 46 47class MemUsageMetric(Metric): 48 """ 49 Metric that collects memory usage in percent. 50 51 Memory usage is collected in percent. Buffers and cached are calculated 52 as free memory. 53 """ 54 def __init__(self, system_facade): 55 super(MemUsageMetric, self).__init__('memory_usage', units='percent') 56 self.system_facade = system_facade 57 58 def collect_metric(self): 59 total_memory = self.system_facade.get_mem_total() 60 free_memory = self.system_facade.get_mem_free_plus_buffers_and_cached() 61 used_memory = total_memory - free_memory 62 usage_percent = (used_memory * 100) / total_memory 63 self.values.append(usage_percent) 64 65class CpuUsageMetric(Metric): 66 """ 67 Metric that collects cpu usage in percent. 68 """ 69 def __init__(self, system_facade): 70 super(CpuUsageMetric, self).__init__('cpu_usage', units='percent') 71 self.last_usage = None 72 self.system_facade = system_facade 73 74 def collect_metric(self): 75 """ 76 Collects CPU usage in percent. 77 78 Since the CPU active time we query is a cumulative metric, the first 79 collection does not actually save a value. It saves the first value to 80 be used for subsequent deltas. 81 """ 82 current_usage = self.system_facade.get_cpu_usage() 83 if self.last_usage is not None: 84 # Compute the percent of active time since the last update to 85 # current_usage. 86 usage_percent = 100 * self.system_facade.compute_active_cpu_time( 87 self.last_usage, current_usage) 88 self.values.append(usage_percent) 89 self.last_usage = current_usage 90 91class AllocatedFileHandlesMetric(Metric): 92 """ 93 Metric that collects the number of allocated file handles. 94 """ 95 def __init__(self, system_facade): 96 super(AllocatedFileHandlesMetric, self).__init__( 97 'allocated_file_handles', units='handles') 98 self.system_facade = system_facade 99 100 def collect_metric(self): 101 self.values.append(self.system_facade.get_num_allocated_file_handles()) 102 103class TemperatureMetric(Metric): 104 """ 105 Metric that collects the max of the temperatures measured on all sensors. 106 """ 107 def __init__(self, system_facade): 108 super(TemperatureMetric, self).__init__('temperature', units='Celsius') 109 self.system_facade = system_facade 110 111 def collect_metric(self): 112 self.values.append(self.system_facade.get_current_temperature_max()) 113 114def create_default_metric_set(system_facade): 115 """ 116 Creates the default set of metrics. 117 118 @param system_facade the system facade to initialize the metrics with. 119 @return a list with Metric instances. 120 """ 121 cpu = CpuUsageMetric(system_facade) 122 mem = MemUsageMetric(system_facade) 123 file_handles = AllocatedFileHandlesMetric(system_facade) 124 temperature = TemperatureMetric(system_facade) 125 peak_cpu = PeakMetric(cpu) 126 peak_mem = PeakMetric(mem) 127 peak_temperature = PeakMetric(temperature) 128 return [cpu, 129 mem, 130 file_handles, 131 temperature, 132 peak_cpu, 133 peak_mem, 134 peak_temperature] 135 136class SystemMetricsCollector(object): 137 """ 138 Collects system metrics. 139 """ 140 def __init__(self, system_facade, metrics = None): 141 """ 142 Initialize with facade and metric classes. 143 144 @param system_facade The system facade to use for querying the system, 145 e.g. system_facade_native.SystemFacadeNative for client tests. 146 @param metrics List of metric instances. If None, the default set will 147 be created. 148 """ 149 self.metrics = (create_default_metric_set(system_facade) 150 if metrics is None else metrics) 151 152 def collect_snapshot(self): 153 """ 154 Collects one snapshot of metrics. 155 """ 156 for metric in self.metrics: 157 metric.collect_metric() 158 159 def write_metrics(self, writer_function): 160 """ 161 Writes the collected metrics using the specified writer function. 162 163 @param writer_function: A function with the following signature: 164 f(description, value, units, higher_is_better) 165 """ 166 for metric in self.metrics: 167 writer_function( 168 description=metric.description, 169 value=metric.values, 170 units=metric.units, 171 higher_is_better=metric.higher_is_better) 172