]> git.ipfire.org Git - collecty.git/blame - src/collecty/plugins/sensors.py
Refectoring of the main classes
[collecty.git] / src / collecty / plugins / sensors.py
CommitLineData
f37913e8 1#!/usr/bin/python3
c389fccf
MT
2# encoding: utf-8
3###############################################################################
4# #
5# collecty - A system statistics collection daemon for IPFire #
6# Copyright (C) 2015 IPFire development team #
7# #
8# This program is free software: you can redistribute it and/or modify #
9# it under the terms of the GNU General Public License as published by #
10# the Free Software Foundation, either version 3 of the License, or #
11# (at your option) any later version. #
12# #
13# This program is distributed in the hope that it will be useful, #
14# but WITHOUT ANY WARRANTY; without even the implied warranty of #
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
16# GNU General Public License for more details. #
17# #
18# You should have received a copy of the GNU General Public License #
19# along with this program. If not, see <http://www.gnu.org/licenses/>. #
20# #
21###############################################################################
22
23from collecty import _collecty
24import os
25import re
26
f37913e8 27from . import base
c389fccf
MT
28
29from ..i18n import _
30
31class GraphTemplateSensorsTemperature(base.GraphTemplate):
32 name = "sensors-temperature"
33
3311f8ad
MT
34 @property
35 def rrd_graph(self):
36 _ = self.locale.translate
37
38 return [
d5d4c0e7
MT
39 # Convert everything to Celsius
40 "CDEF:value_c=value,273.15,-",
41 "CDEF:critical_c=critical,273.15,-",
42 "CDEF:high_c=high,273.15,-",
43 "CDEF:low_c=low,273.15,-",
3311f8ad
MT
44
45 # Change colour when the value gets above high
d5d4c0e7
MT
46 "CDEF:value_c_high=value_c,high_c,GT,value_c,UNKN,IF",
47 "CDEF:value_c_normal=value_c,high_c,GT,UNKN,value_c,IF",
3311f8ad 48
3311f8ad 49 # Get data points for the threshold lines
d5d4c0e7
MT
50 "VDEF:critical_c_line=critical_c,MINIMUM",
51 "VDEF:low_c_line=low_c,MAXIMUM",
3311f8ad
MT
52
53 # Draw the temperature value
d5d4c0e7
MT
54 "LINE3:value_c_high#ff0000",
55 "LINE2:value_c_normal#00ff00:%-15s" % _("Temperature"),
3311f8ad
MT
56
57 # Draw the legend
d5d4c0e7
MT
58 "GPRINT:value_c_cur:%10.2lf °C\l",
59 "GPRINT:value_c_avg: %-15s %%6.2lf °C\l" % _("Average"),
60 "GPRINT:value_c_max: %-15s %%6.2lf °C\l" % _("Maximum"),
61 "GPRINT:value_c_min: %-15s %%6.2lf °C\l" % _("Minimum"),
3311f8ad
MT
62
63 # Empty line
64 "COMMENT: \\n",
65
66 # Draw boundary lines
67 "COMMENT:%s\:" % _("Temperature Thresholds"),
d5d4c0e7
MT
68 "HRULE:critical_c_line#000000:%-15s" % _("Critical"),
69 "GPRINT:critical_c_line:%6.2lf °C\\r",
70 "HRULE:low_c_line#0000ff:%-15s" % _("Low"),
71 "GPRINT:low_c_line:%6.2lf °C\\r",
3311f8ad 72 ]
c389fccf
MT
73
74 @property
75 def graph_title(self):
3311f8ad 76 _ = self.locale.translate
c389fccf
MT
77 return _("Temperature (%s)") % self.object.sensor.name
78
79 @property
80 def graph_vertical_label(self):
3311f8ad 81 _ = self.locale.translate
c389fccf
MT
82 return _("° Celsius")
83
84
85class GraphTemplateSensorsProcessorTemperature(base.GraphTemplate):
86 name = "processor-temperature"
87
d5d4c0e7
MT
88 core_colours = [
89 "#ff000033",
90 "#0000ff33",
91 "#00ff0033",
92 "#0000ff33",
93 ]
c389fccf
MT
94
95 def get_temperature_sensors(self):
96 return self.plugin.get_detected_sensor_objects("coretemp-*")
97
d5d4c0e7
MT
98 def get_objects(self, *args, **kwargs):
99 sensors = self.get_temperature_sensors()
c389fccf 100
d5d4c0e7 101 return list(sensors)
c389fccf
MT
102
103 @property
104 def rrd_graph(self):
3311f8ad 105 _ = self.locale.translate
c389fccf
MT
106 rrd_graph = []
107
d5d4c0e7
MT
108 counter = 0
109 ids = []
c389fccf 110
d5d4c0e7
MT
111 for core in self.objects:
112 id = "core%s" % counter
113 counter += 1
114 ids.append(id)
c389fccf 115
d5d4c0e7 116 rrd_graph += core.make_rrd_defs(id) + [
c389fccf 117 # Convert everything to celsius
d5d4c0e7
MT
118 "CDEF:%s_value_c=%s_value,273.15,-" % (id, id),
119 "CDEF:%s_critical_c=%s_critical,273.15,-" % (id, id),
120 "CDEF:%s_high_c=%s_high,273.15,-" % (id, id),
c389fccf
MT
121 ]
122
d5d4c0e7
MT
123 # Compute the temperature of the processor
124 # by taking the average of all cores
125 all_core_values = ("%s_value_c" % id for id in ids)
126 rrd_graph += [
127 "CDEF:all_value_c=%s,%s,AVG" % (",".join(all_core_values), len(ids)),
128 ]
c389fccf 129
d5d4c0e7
MT
130 # Get the high threshold of the first core
131 # (assuming that all cores have the same threshold)
132 for id in ids:
133 rrd_graph.append("CDEF:all_high_c=%s_high_c" % id)
134 break
c389fccf
MT
135
136 rrd_graph += [
c389fccf 137 # Change colour when the value gets above high
d5d4c0e7
MT
138 "CDEF:all_value_c_high=all_value_c,all_high_c,GT,all_value_c,UNKN,IF",
139 "CDEF:all_value_c_normal=all_value_c,all_high_c,GT,UNKN,all_value_c,IF",
c389fccf 140
d5d4c0e7
MT
141 "LINE3:all_value_c_high#FF0000",
142 "LINE3:all_value_c_normal#000000:%-15s\l" % _("Temperature"),
c389fccf 143
d5d4c0e7
MT
144 "GPRINT:all_value_c_avg: %-15s %%6.2lf °C\l" % _("Average"),
145 "GPRINT:all_value_c_max: %-15s %%6.2lf °C\l" % _("Maximum"),
146 "GPRINT:all_value_c_min: %-15s %%6.2lf °C\l" % _("Minimum"),
c389fccf
MT
147 ]
148
d5d4c0e7
MT
149 for id, core, colour in zip(ids, self.objects, self.core_colours):
150 rrd_graph += [
c389fccf
MT
151 # TODO these lines were supposed to be dashed, but that
152 # didn't really work here
d5d4c0e7 153 "LINE2:%s_value_c%s:%-10s" % (id, colour, core.sensor.label),
c389fccf
MT
154 ]
155
c389fccf 156 # Draw the critical line
d5d4c0e7
MT
157 for id in ids:
158 rrd_graph += [
159 "HRULE:%s_critical_c_min#000000:%-15s" % (id, _("Critical")),
160 "GPRINT:%s_critical_c_min:%%6.2lf °C\\r" % id,
161 ]
162 break
c389fccf
MT
163
164 return rrd_graph
165
166 @property
167 def graph_title(self):
3311f8ad 168 _ = self.locale.translate
c389fccf
MT
169 return _("Processor")
170
171 @property
172 def graph_vertical_label(self):
3311f8ad 173 _ = self.locale.translate
c389fccf
MT
174 return _("Temperature")
175
176
177class SensorBaseObject(base.Object):
178 def init(self, sensor):
179 self.sensor = sensor
180
181 def __repr__(self):
182 return "<%s %s (%s)>" % (self.__class__.__name__, self.sensor.name, self.sensor.label)
183
184 @property
185 def id(self):
186 return "-".join((self.sensor.name, self.sensor.label))
187
188 @property
189 def type(self):
190 return self.sensor.type
191
192
193class SensorTemperatureObject(SensorBaseObject):
194 rrd_schema = [
195 "DS:value:GAUGE:0:U",
196 "DS:critical:GAUGE:0:U",
197 "DS:low:GAUGE:0:U",
198 "DS:high:GAUGE:0:U",
199 ]
200
201 def collect(self):
202 assert self.type == "temperature"
203
204 return (
205 self.sensor.value,
206 self.critical,
207 self.low,
208 self.high,
209 )
210
211 @property
212 def critical(self):
213 try:
214 return self.sensor.critical
215 except AttributeError:
216 return "NaN"
217
218 @property
219 def low(self):
220 try:
221 return self.sensor.minimum
222 except AttributeError:
223 return "NaN"
224
225 @property
226 def high(self):
227 try:
228 return self.sensor.high
229 except AttributeError:
230 return "NaN"
231
232
233class SensorVoltageObject(SensorBaseObject):
234 rrd_schema = [
235 "DS:value:GAUGE:0:U",
236 "DS:minimum:GAUGE:0:U",
237 "DS:maximum:GAUGE:0:U",
238 ]
239
240 def collect(self):
241 assert self.type == "voltage"
242
243 return (
244 self.sensor.value,
245 self.minimum,
246 self.maximum,
247 )
248
249 @property
250 def minimum(self):
251 try:
252 return self.sensor.minimum
253 except AttributeError:
254 return "NaN"
255
256 @property
257 def maximum(self):
258 try:
259 return self.sensor.maximum
260 except AttributeError:
261 return "NaN"
262
263
264class SensorFanObject(SensorBaseObject):
265 rrd_schema = [
266 "DS:value:GAUGE:0:U",
267 "DS:minimum:GAUGE:0:U",
268 "DS:maximum:GAUGE:0:U",
269 ]
270
271 def collect(self):
272 assert self.type == "fan"
273
274 return (
275 self.sensor.value,
276 self.minimum,
277 self.maximum,
278 )
279
280 @property
d0588abe 281 def minimum(self):
c389fccf
MT
282 try:
283 return self.sensor.minimum
284 except AttributeError:
285 return "NaN"
286
287 @property
288 def maximum(self):
289 try:
290 return self.sensor.maximum
291 except AttributeError:
292 return "NaN"
293
294
295class SensorsPlugin(base.Plugin):
296 name = "sensors"
297 description = "Sensors Plugin"
298
299 templates = [
300 GraphTemplateSensorsProcessorTemperature,
301 GraphTemplateSensorsTemperature,
302 ]
303
304 def init(self):
305 # Initialise the sensors library.
306 _collecty.sensors_init()
307
308 def __del__(self):
309 _collecty.sensors_cleanup()
310
311 @property
312 def objects(self):
313 return self.get_detected_sensor_objects()
314
315 def get_detected_sensor_objects(self, what=None):
316 for sensor in _collecty.get_detected_sensors(what):
317 if sensor.type == "temperature":
318 yield SensorTemperatureObject(self, sensor)
319
320 elif sensor.type == "voltage":
321 yield SensorVoltageObject(self, sensor)
322
323 elif sensor.type == "fan":
324 yield SensorFanObject(self, sensor)