]> git.ipfire.org Git - people/ms/westferry.git/blame - src/westferry/handlers/analytics.py
analytics: Add network graphs
[people/ms/westferry.git] / src / westferry / handlers / analytics.py
CommitLineData
21a66327
MT
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
22import datetime
23import collecty.client
24import mimetypes
25import tornado.web
26
27from . import base
a6144752
MT
28from .. import ui
29
3fc6d806 30from ..i18n import N_
a6144752
MT
31
32class 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
30806514
MT
43 # Network
44 m.add_handler(AnalyticsNetworkOverviewHandler)
45
a6144752
MT
46 # System
47 m.add_handler(AnalyticsSystemOverviewHandler)
48
49 return m
50
03f518c7
MT
51 def render_graphs(self, graphs):
52 self.render("graphs.html", graphs=graphs)
53
a6144752
MT
54
55class AnalyticsOverviewHandler(AnalyticsBaseHandler):
56 url = r"/analytics"
57 title = N_("Overview")
58
59 def get(self):
60 self.render("base.html")
61
62
30806514
MT
63class 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 return m
82
83
84class AnalyticsNetworkOverviewHandler(AnalyticsNetworkBaseHandler):
85 url = r"/analytics/network"
86 title = N_("Network")
87
88 def get(self):
89 self.render("base.html")
90
91
92class AnalyticsNetworkConnectionsBaseHandler(AnalyticsBaseHandler):
93 @property
94 def menu(self):
95 _ = self.locale.translate
96
97 m = ui.menu.Menu(self, _("Connections"))
98
99 # Back...
100 m.add_handler(AnalyticsNetworkOverviewHandler, title=_("Back..."))
101 m.add_divider()
102
103 # Overview
104 m.add_handler(AnalyticsNetworkConnectionsOverviewHandler, title=_("Overview"))
105 m.add_divider()
106
107 # Protocol States
108 s = m.add_submenu(_("Procotol States"))
109 s.add_handler(AnalyticsNetworkConnectionsStatesTCPHandler)
110 s.add_handler(AnalyticsNetworkConnectionsStatesSCTPHandler)
111 s.add_handler(AnalyticsNetworkConnectionsStatesDCCPHandler)
112
113 return m
114
115
116class AnalyticsNetworkConnectionsOverviewHandler(AnalyticsNetworkConnectionsBaseHandler):
117 url = r"/analytics/network/connections"
118 title = N_("Connections")
119
120 def get(self):
121 _ = self.locale.translate
122
123 graphs = [
124 ui.graphs.Graph(self, "conntrack-layer3-protocols"),
125 ui.graphs.Graph(self, "conntrack-layer4-protocols"),
126 ]
127
128 self.render_graphs(graphs)
129
130
131class AnalyticsNetworkConnectionsStatesTCPHandler(AnalyticsNetworkConnectionsBaseHandler):
132 url = r"/analytics/network/connections/states/tcp"
133 title = N_("TCP")
134
135 def get(self):
136 _ = self.locale.translate
137
138 graphs = [
139 ui.graphs.Graph(self, "conntrack-protocol-states", "tcp"),
140 ]
141
142 self.render_graphs(graphs)
143
144
145class AnalyticsNetworkConnectionsStatesSCTPHandler(AnalyticsNetworkConnectionsBaseHandler):
146 url = r"/analytics/network/connections/states/sctp"
147 title = N_("SCTP")
148
149 def get(self):
150 _ = self.locale.translate
151
152 graphs = [
153 ui.graphs.Graph(self, "conntrack-protocol-states", "sctp"),
154 ]
155
156 self.render_graphs(graphs)
157
158
159class AnalyticsNetworkConnectionsStatesDCCPHandler(AnalyticsNetworkConnectionsBaseHandler):
160 url = r"/analytics/network/connections/states/dccp"
161 title = N_("DCCP")
162
163 def get(self):
164 _ = self.locale.translate
165
166 graphs = [
167 ui.graphs.Graph(self, "conntrack-protocol-states", "dccp"),
168 ]
169
170 self.render_graphs(graphs)
171
172
a6144752
MT
173class AnalyticsSystemBaseHandler(AnalyticsBaseHandler):
174 @property
175 def menu(self):
176 _ = self.locale.translate
177
178 m = ui.menu.Menu(self, _("System"))
179
180 # Back...
181 m.add_handler(AnalyticsOverviewHandler, title=_("Back..."))
182 m.add_divider()
183
184 # Overview
185 m.add_handler(AnalyticsSystemOverviewHandler, title=_("Overview"))
186 m.add_divider()
187
03f518c7 188 # Most interesting items
a6144752
MT
189 m.add_handler(AnalyticsSystemProcessorsHandler)
190 m.add_handler(AnalyticsSystemMemoryHandler)
03f518c7
MT
191 m.add_handler(AnalyticsSystemTemperaturesHandler)
192
193 # Others
194 s = m.add_submenu(_("More"))
195 s.add_handler(AnalyticsSystemEntropyHandler)
a6144752
MT
196
197 return m
198
199
200class AnalyticsSystemOverviewHandler(AnalyticsSystemBaseHandler):
201 url = r"/analytics/system"
202 title = N_("System")
203
03f518c7
MT
204 def get(self):
205 self.render("base.html")
206
a6144752
MT
207
208class AnalyticsSystemProcessorsHandler(AnalyticsSystemBaseHandler):
209 url = r"/analytics/system/processors"
210 title = N_("Processors")
211
03f518c7
MT
212 def get(self):
213 _ = self.locale.translate
214
215 graphs = [
216 ui.graphs.Graph(self, "processor"),
217 ui.graphs.Graph(self, "processor-temperature"),
218 ui.graphs.Graph(self, "cpufreq"),
219 ui.graphs.Graph(self, "loadavg"),
220 ]
221
222 self.render_graphs(graphs)
223
a6144752
MT
224
225class AnalyticsSystemMemoryHandler(AnalyticsSystemBaseHandler):
226 url = r"/analytics/system/memory"
227 title = N_("Memory")
228
03f518c7
MT
229 def get(self):
230 _ = self.locale.translate
231
232 graphs = [
233 ui.graphs.Graph(self, "memory"),
234 ]
235
236 self.render_graphs(graphs)
237
238
239class AnalyticsSystemTemperaturesHandler(AnalyticsSystemBaseHandler):
240 url = r"/analytics/system/temperatures"
241 title = N_("Temperatures")
242
243 def get(self):
244 _ = self.locale.translate
245
246 graphs = [
247 ui.graphs.Graph(self, "sensors-temperature"),
248 ui.graphs.Graph(self, "processor-temperature"),
249 ]
250
251 self.render_graphs(graphs)
252
253
254class AnalyticsSystemEntropyHandler(AnalyticsSystemBaseHandler):
255 url = r"/analytics/system/entropy"
256 title = N_("Entropy")
257
258 def get(self):
259 _ = self.locale.translate
260
261 graphs = [
262 ui.graphs.Graph(self, "entropy"),
263 ]
264
265 self.render_graphs(graphs)
266
21a66327
MT
267
268class GraphExportHandler(base.BaseHandler):
269 VALID_INTERVALS = ("hour", "day", "month", "week", "year")
270 DEFAULT_INTERVAL = "day"
271
272 SUPPORTED_FORMATS = ("pdf", "png", "svg")
273
03f518c7 274 url = r"/graph/([\w\-]+)(?:/([\w\d\.]+))?\.(%s)" % "|".join(SUPPORTED_FORMATS)
21a66327
MT
275
276 def get(self, template_name, object_id, format):
277 # Get the requested dimensions of the image
278 height = self.get_argument_int("height", None)
279 width = self.get_argument_int("width", None)
280
281 # Get the requested interval
282 interval = self.get_argument("interval", self.DEFAULT_INTERVAL)
283 if interval and not interval in self.VALID_INTERVALS:
284 raise tornado.web.HTTPError(400, _("Invalid interval: %s") % interval)
285
03f518c7
MT
286 # Create the graph object
287 g = ui.graphs.Graph(self, template_name, object_id=object_id)
288
21a66327 289 # Generate the graph image
03f518c7
MT
290 image = g.generate_graph(format=format.upper(), interval=interval,
291 height=height, width=width)
21a66327
MT
292
293 # Set the HTTP headers
294 self._make_headers(format, template_name, object_id)
295
296 # Deliver the content
03f518c7 297 self.finish(image.get("image"))
21a66327
MT
298
299 def _make_headers(self, extension, template_name, object_id):
300 # Determine the mime type
301 mimetype = mimetypes.types_map.get(".%s" % extension, "application/octet-stream")
302 self.set_header("Content-Type", mimetype)
303
304 # Add the timestamp when this graph was generated
305 now = datetime.datetime.now()
306
307 # Put together the filename (for downloads)
308 filename = [self.backend.system.hostname, template_name, object_id, now.isoformat()]
309 filename = "%s.%s" % ("-".join((e for e in filename if e)), extension)
310
311 if extension == "pdf":
312 self.set_header("Content-Disposition", "attachment; filename=%s" % filename)
313 else:
314 self.set_header("Content-Disposition", "inline; filename=%s" % filename)
03f518c7
MT
315
316
317class GraphHandler(base.BaseHandler):
318 url = r"/graph/([\w\-]+)(?:/([\w\d\.]+))?"
319
320 def get(self, template, object_id):
321 graph = ui.graphs.Graph(self, template, object_id=object_id)
322
323 self.render("graph.html", graph=graph)