]> git.ipfire.org Git - people/ms/westferry.git/blob - src/westferry/handlers/analytics.py
3b412656d0a983b39b20eb88f65518ea5c1a919f
[people/ms/westferry.git] / src / westferry / handlers / analytics.py
1 #!/usr/bin/python3
2 ###############################################################################
3 # #
4 # Westferry - The IPFire web user interface #
5 # Copyright (C) 2015 IPFire development team #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 import datetime
23 import collecty.client
24 import mimetypes
25 import tornado.web
26
27 from . import base
28 from .. import ui
29
30 from ..i18n import N_
31
32 class AnalyticsBaseHandler(base.BaseHandler):
33 @property
34 def menu(self):
35 _ = self.locale.translate
36
37 m = ui.menu.Menu(self, _("Analytics"))
38
39 # Overview
40 m.add_handler(AnalyticsOverviewHandler)
41 m.add_divider()
42
43 # Network
44 m.add_handler(AnalyticsNetworkOverviewHandler)
45
46 # System
47 m.add_handler(AnalyticsSystemOverviewHandler)
48
49 return m
50
51 def render_graphs(self, graphs):
52 self.render("graphs.html", graphs=graphs)
53
54
55 class AnalyticsOverviewHandler(AnalyticsBaseHandler):
56 url = r"/analytics"
57 title = N_("Overview")
58
59 def get(self):
60 self.render("base.html")
61
62
63 class AnalyticsNetworkBaseHandler(AnalyticsBaseHandler):
64 @property
65 def menu(self):
66 _ = self.locale.translate
67
68 m = ui.menu.Menu(self, _("Network"))
69
70 # Back...
71 m.add_handler(AnalyticsOverviewHandler, title=_("Back..."))
72 m.add_divider()
73
74 # Overview
75 m.add_handler(AnalyticsNetworkOverviewHandler, title=_("Overview"))
76 m.add_divider()
77
78 # Connections
79 m.add_handler(AnalyticsNetworkConnectionsOverviewHandler)
80
81 # Fragmentation
82 m.add_handler(AnalyticsNetworkIPFragmentationHandler)
83
84 return m
85
86
87 class AnalyticsNetworkOverviewHandler(AnalyticsNetworkBaseHandler):
88 url = r"/analytics/network"
89 title = N_("Network")
90
91 def get(self):
92 self.render("base.html")
93
94
95 class AnalyticsNetworkConnectionsBaseHandler(AnalyticsBaseHandler):
96 @property
97 def menu(self):
98 _ = self.locale.translate
99
100 m = ui.menu.Menu(self, _("Connections"))
101
102 # Back...
103 m.add_handler(AnalyticsNetworkOverviewHandler, title=_("Back..."))
104 m.add_divider()
105
106 # Overview
107 m.add_handler(AnalyticsNetworkConnectionsOverviewHandler, title=_("Overview"))
108 m.add_divider()
109
110 # Protocol States
111 s = m.add_submenu(_("Procotol States"))
112 s.add_handler(AnalyticsNetworkConnectionsStatesTCPHandler)
113 s.add_handler(AnalyticsNetworkConnectionsStatesSCTPHandler)
114 s.add_handler(AnalyticsNetworkConnectionsStatesDCCPHandler)
115
116 return m
117
118
119 class AnalyticsNetworkConnectionsOverviewHandler(AnalyticsNetworkConnectionsBaseHandler):
120 url = r"/analytics/network/connections"
121 title = N_("Connections")
122
123 def get(self):
124 _ = self.locale.translate
125
126 graphs = [
127 ui.graphs.Graph(self, "conntrack-layer3-protocols"),
128 ui.graphs.Graph(self, "conntrack-layer4-protocols"),
129 ]
130
131 self.render_graphs(graphs)
132
133
134 class AnalyticsNetworkConnectionsStatesTCPHandler(AnalyticsNetworkConnectionsBaseHandler):
135 url = r"/analytics/network/connections/states/tcp"
136 title = N_("TCP")
137
138 def get(self):
139 _ = self.locale.translate
140
141 graphs = [
142 ui.graphs.Graph(self, "conntrack-protocol-states", "tcp"),
143 ]
144
145 self.render_graphs(graphs)
146
147
148 class AnalyticsNetworkConnectionsStatesSCTPHandler(AnalyticsNetworkConnectionsBaseHandler):
149 url = r"/analytics/network/connections/states/sctp"
150 title = N_("SCTP")
151
152 def get(self):
153 _ = self.locale.translate
154
155 graphs = [
156 ui.graphs.Graph(self, "conntrack-protocol-states", "sctp"),
157 ]
158
159 self.render_graphs(graphs)
160
161
162 class AnalyticsNetworkConnectionsStatesDCCPHandler(AnalyticsNetworkConnectionsBaseHandler):
163 url = r"/analytics/network/connections/states/dccp"
164 title = N_("DCCP")
165
166 def get(self):
167 _ = self.locale.translate
168
169 graphs = [
170 ui.graphs.Graph(self, "conntrack-protocol-states", "dccp"),
171 ]
172
173 self.render_graphs(graphs)
174
175
176 class AnalyticsNetworkIPFragmentationHandler(AnalyticsNetworkBaseHandler):
177 url = r"/analytics/network/fragmentation"
178 title = N_("Fragmentation")
179
180 def get(self):
181 _ = self.locale.translate
182
183 graphs = [
184 ui.graphs.Graph(self, "ipv6-fragmentation"),
185 ui.graphs.Graph(self, "ipv4-fragmentation"),
186 ]
187
188 self.render_graphs(graphs)
189
190
191 class AnalyticsSystemBaseHandler(AnalyticsBaseHandler):
192 @property
193 def menu(self):
194 _ = self.locale.translate
195
196 m = ui.menu.Menu(self, _("System"))
197
198 # Back...
199 m.add_handler(AnalyticsOverviewHandler, title=_("Back..."))
200 m.add_divider()
201
202 # Overview
203 m.add_handler(AnalyticsSystemOverviewHandler, title=_("Overview"))
204 m.add_divider()
205
206 # Most interesting items
207 m.add_handler(AnalyticsSystemProcessorsHandler)
208 m.add_handler(AnalyticsSystemMemoryHandler)
209 m.add_handler(AnalyticsSystemTemperaturesHandler)
210
211 # Others
212 s = m.add_submenu(_("More"))
213 s.add_handler(AnalyticsSystemEntropyHandler)
214 s.add_handler(AnalyticsSystemContextSwitchesHandler)
215 s.add_handler(AnalyticsSystemInterruptsHandler)
216
217 return m
218
219
220 class AnalyticsSystemOverviewHandler(AnalyticsSystemBaseHandler):
221 url = r"/analytics/system"
222 title = N_("System")
223
224 def get(self):
225 self.render("base.html")
226
227
228 class AnalyticsSystemProcessorsHandler(AnalyticsSystemBaseHandler):
229 url = r"/analytics/system/processors"
230 title = N_("Processors")
231
232 def get(self):
233 _ = self.locale.translate
234
235 graphs = [
236 ui.graphs.Graph(self, "processor"),
237 ui.graphs.Graph(self, "processor-temperature"),
238 ui.graphs.Graph(self, "cpufreq"),
239 ui.graphs.Graph(self, "loadavg"),
240 ]
241
242 self.render_graphs(graphs)
243
244
245 class AnalyticsSystemMemoryHandler(AnalyticsSystemBaseHandler):
246 url = r"/analytics/system/memory"
247 title = N_("Memory")
248
249 def get(self):
250 _ = self.locale.translate
251
252 graphs = [
253 ui.graphs.Graph(self, "memory"),
254 ]
255
256 self.render_graphs(graphs)
257
258
259 class AnalyticsSystemTemperaturesHandler(AnalyticsSystemBaseHandler):
260 url = r"/analytics/system/temperatures"
261 title = N_("Temperatures")
262
263 def get(self):
264 _ = self.locale.translate
265
266 graphs = [
267 ui.graphs.Graph(self, "sensors-temperature"),
268 ui.graphs.Graph(self, "processor-temperature"),
269 ]
270
271 self.render_graphs(graphs)
272
273
274 class AnalyticsSystemEntropyHandler(AnalyticsSystemBaseHandler):
275 url = r"/analytics/system/entropy"
276 title = N_("Entropy")
277
278 def get(self):
279 _ = self.locale.translate
280
281 graphs = [
282 ui.graphs.Graph(self, "entropy"),
283 ]
284
285 self.render_graphs(graphs)
286
287
288 class AnalyticsSystemContextSwitchesHandler(AnalyticsSystemBaseHandler):
289 url = r"/analytics/system/context-switches"
290 title = N_("Context Switches")
291
292 def get(self):
293 _ = self.locale.translate
294
295 graphs = [
296 ui.graphs.Graph(self, "context-switches"),
297 ]
298
299 self.render_graphs(graphs)
300
301
302 class AnalyticsSystemInterruptsHandler(AnalyticsSystemBaseHandler):
303 url = r"/analytics/system/interrupts"
304 title = N_("Interrupts")
305
306 def get(self):
307 _ = self.locale.translate
308
309 graphs = [
310 ui.graphs.Graph(self, "system-interrupts"),
311 ]
312
313 self.render_graphs(graphs)
314
315
316 class GraphExportHandler(base.BaseHandler):
317 VALID_INTERVALS = ("hour", "day", "month", "week", "year")
318 DEFAULT_INTERVAL = "day"
319
320 SUPPORTED_FORMATS = ("pdf", "png", "svg")
321
322 url = r"/graph/([\w\-]+)(?:/([\w\d\.]+))?\.(%s)" % "|".join(SUPPORTED_FORMATS)
323
324 def get(self, template_name, object_id, format):
325 # Get the requested dimensions of the image
326 height = self.get_argument_int("height", None)
327 width = self.get_argument_int("width", None)
328
329 # Get the requested interval
330 interval = self.get_argument("interval", self.DEFAULT_INTERVAL)
331 if interval and not interval in self.VALID_INTERVALS:
332 raise tornado.web.HTTPError(400, _("Invalid interval: %s") % interval)
333
334 # Create the graph object
335 g = ui.graphs.Graph(self, template_name, object_id=object_id)
336
337 # Generate the graph image
338 kwargs = {
339 "format" : format.upper(),
340 "interval" : interval,
341 "height" : height,
342 "width" : width,
343
344 # Include the title in the PDF exports
345 "with_title" : format == "pdf",
346 }
347 image = g.generate_graph(**kwargs)
348
349 # Set the HTTP headers
350 self._make_headers(format, template_name, object_id)
351
352 # Deliver the content
353 self.finish(image.get("image"))
354
355 def _make_headers(self, extension, template_name, object_id):
356 # Determine the mime type
357 mimetype = mimetypes.types_map.get(".%s" % extension, "application/octet-stream")
358 self.set_header("Content-Type", mimetype)
359
360 # Add the timestamp when this graph was generated
361 now = datetime.datetime.now()
362
363 # Put together the filename (for downloads)
364 filename = [self.backend.system.hostname, template_name, object_id, now.isoformat()]
365 filename = "%s.%s" % ("-".join((e for e in filename if e)), extension)
366
367 if extension == "pdf":
368 self.set_header("Content-Disposition", "attachment; filename=%s" % filename)
369 else:
370 self.set_header("Content-Disposition", "inline; filename=%s" % filename)
371
372
373 class GraphHandler(base.BaseHandler):
374 url = r"/graph/([\w\-]+)(?:/([\w\d\.]+))?"
375
376 def get(self, template, object_id):
377 graph = ui.graphs.Graph(self, template, object_id=object_id)
378
379 self.render("graph.html", graph=graph)