graph templates: Make some atttibutes easier to set
[collecty.git] / src / collecty / plugins / interface.py
1 #!/usr/bin/python
2 ###############################################################################
3 #                                                                             #
4 # collecty - A system statistics collection daemon for IPFire                 #
5 # Copyright (C) 2012 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 from __future__ import division
23
24 import os
25
26 import base
27
28 from ..i18n import _
29
30 SYS_CLASS_NET = "/sys/class/net"
31
32 COLOUR_RX = "B22222"
33 COLOUR_RX_AREA = "%sAA" % COLOUR_RX
34 COLOUR_TX = "228B22"
35 COLOUR_TX_AREA = "%sAA" % COLOUR_TX
36
37 class GraphTemplateInterfaceBits(base.GraphTemplate):
38         name = "interface-bits"
39
40         @property
41         def rrd_graph(self):
42                 return [
43                         "DEF:bytes_rx=%(file)s:bytes_rx:AVERAGE",
44                         "DEF:bytes_tx=%(file)s:bytes_tx:AVERAGE",
45
46                         # Convert everything into bits.
47                         "CDEF:bits_rx=bytes_rx,8,*",
48                         "CDEF:bits_tx=bytes_tx,8,*",
49
50                         # Compute 95% lines.
51                         "VDEF:bits_rx_95p=bits_rx,95,PERCENT",
52                         "VDEF:bits_tx_95p=bits_tx,95,PERCENT",
53
54                         # Draw the received area.
55                         "AREA:bits_rx#%s:%-15s" % (COLOUR_RX_AREA, _("Received")),
56                         "VDEF:bits_rx_min=bits_rx,MINIMUM",
57                         "VDEF:bits_rx_max=bits_rx,MAXIMUM",
58                         "VDEF:bits_rx_avg=bits_rx,AVERAGE",
59                         "GPRINT:bits_rx_max:%12s\: " % _("Maximum") + _("%8.2lf %sbps"),
60                         "GPRINT:bits_rx_min:%12s\: " % _("Minimum") + _("%8.2lf %sbps"),
61                         "GPRINT:bits_rx_avg:%12s\: " % _("Average") + _("%8.2lf %sbps") + "\\n",
62
63                         # Draw the transmitted area.
64                         "AREA:bits_tx#%s:%-15s" % (COLOUR_TX_AREA, _("Transmitted")),
65                         "VDEF:bits_tx_min=bits_tx,MINIMUM",
66                         "VDEF:bits_tx_max=bits_tx,MAXIMUM",
67                         "VDEF:bits_tx_avg=bits_tx,AVERAGE",
68                         "GPRINT:bits_tx_max:%12s\: " % _("Maximum") + _("%8.2lf %sbps"),
69                         "GPRINT:bits_tx_min:%12s\: " % _("Minimum") + _("%8.2lf %sbps"),
70                         "GPRINT:bits_tx_avg:%12s\: " % _("Average") + _("%8.2lf %sbps") + "\\n",
71
72                         # Draw outlines.
73                         "LINE1:bits_rx#%s" % COLOUR_RX,
74                         "LINE1:bits_tx#%s" % COLOUR_TX,
75
76                         # Draw the 95% lines.
77                         "COMMENT:--- %s ---\\n" % _("95th percentile"),
78                         "LINE2:bits_rx_95p#%s:%-15s" % (COLOUR_RX, _("Received")),
79                         "GPRINT:bits_rx_95p:%s" % _("%8.2lf %sbps") + "\\n",
80                         "LINE2:bits_tx_95p#%s:%-15s" % (COLOUR_TX, _("Transmitted")),
81                         "GPRINT:bits_tx_95p:%s" % _("%8.2lf %sbps") + "\\n",
82                 ]
83
84         @property
85         def graph_title(self):
86                 return _("Bandwidth usage on %(interface)s")
87
88         @property
89         def graph_vertical_label(self):
90                 return _("Bit/s")
91
92
93 class GraphTemplateInterfacePackets(base.GraphTemplate):
94         name = "interface-packets"
95
96         @property
97         def rrd_graph(self):
98                 return [
99                         "DEF:packets_rx=%(file)s:packets_rx:AVERAGE",
100                         "DEF:packets_tx=%(file)s:packets_tx:AVERAGE",
101
102                         # Draw the received area.
103                         "AREA:packets_rx#%s:%-15s" % (COLOUR_RX_AREA, _("Received")),
104                         "VDEF:packets_rx_min=packets_rx,MINIMUM",
105                         "VDEF:packets_rx_max=packets_rx,MAXIMUM",
106                         "VDEF:packets_rx_avg=packets_rx,AVERAGE",
107                         "GPRINT:packets_rx_max:%12s\: " % _("Maximum") + _("%8.0lf %spps"),
108                         "GPRINT:packets_rx_min:%12s\: " % _("Minimum") + _("%8.0lf %spps"),
109                         "GPRINT:packets_rx_avg:%12s\: " % _("Average") + _("%8.2lf %spps") + "\\n",
110
111                         # Draw the transmitted area.
112                         "AREA:packets_tx#%s:%-15s" % (COLOUR_TX_AREA, _("Transmitted")),
113                         "VDEF:packets_tx_min=packets_tx,MINIMUM",
114                         "VDEF:packets_tx_max=packets_tx,MAXIMUM",
115                         "VDEF:packets_tx_avg=packets_tx,AVERAGE",
116                         "GPRINT:packets_tx_max:%12s\: " % _("Maximum") + _("%8.0lf %spps"),
117                         "GPRINT:packets_tx_min:%12s\: " % _("Minimum") + _("%8.0lf %spps"),
118                         "GPRINT:packets_tx_avg:%12s\: " % _("Average") + _("%8.2lf %spps") + "\\n",
119
120                         # Draw outlines of the areas on top.
121                         "LINE1:packets_rx#%s" % COLOUR_RX,
122                         "LINE1:packets_tx#%s" % COLOUR_TX,
123                 ]
124
125         @property
126         def graph_title(self):
127                 return _("Transferred packets on %(interface)s")
128
129         @property
130         def graph_vertical_label(self):
131                 return _("Packets/s")
132
133
134 class GraphTemplateInterfaceErrors(base.GraphTemplate):
135         name = "interface-errors"
136
137         @property
138         def rrd_graph(self):
139                 return [
140                         "DEF:errors_rx=%(file)s:errors_rx:AVERAGE",
141                         "DEF:errors_tx=%(file)s:errors_tx:AVERAGE",
142                         "DEF:dropped_rx=%(file)s:dropped_rx:AVERAGE",
143                         "DEF:dropped_tx=%(file)s:dropped_tx:AVERAGE",
144                         "DEF:collisions=%(file)s:collisions:AVERAGE",
145
146                         # Invert the transmitted packets to create upside down graph.
147                         "CDEF:errors_tx_inv=errors_tx,-1,*",
148                         "CDEF:dropped_tx_inv=dropped_tx,-1,*",
149
150                         # Draw the receive errors.
151                         "AREA:errors_rx#228B2277:%-15s" % _("Receive errors"),
152                         "VDEF:errors_rx_min=errors_rx,MINIMUM",
153                         "VDEF:errors_rx_max=errors_rx,MAXIMUM",
154                         "VDEF:errors_rx_avg=errors_rx,AVERAGE",
155                         "GPRINT:errors_rx_max:%12s\: " % _("Maximum") + _("%8.0lf %spps"),
156                         "GPRINT:errors_rx_min:%12s\: " % _("Minimum") + _("%8.0lf %spps"),
157                         "GPRINT:errors_rx_avg:%12s\: " % _("Average") + _("%8.2lf %spps") + "\\n",
158                         "LINE1:errors_rx#228B22",
159
160                         # Draw the transmit errors.
161                         "AREA:errors_tx_inv#B2222277:%-15s" % _("Transmit errors"),
162                         "VDEF:errors_tx_min=errors_tx,MINIMUM",
163                         "VDEF:errors_tx_max=errors_tx,MAXIMUM",
164                         "VDEF:errors_tx_avg=errors_tx,AVERAGE",
165                         "GPRINT:errors_tx_max:%12s\: " % _("Maximum") + _("%8.0lf %spps"),
166                         "GPRINT:errors_tx_min:%12s\: " % _("Minimum") + _("%8.0lf %spps"),
167                         "GPRINT:errors_tx_avg:%12s\: " % _("Average") + _("%8.2lf %spps") + "\\n",
168                         "LINE1:errors_tx_inv#B22222",
169
170                         # Draw the receive drops.
171                         "LINE2:dropped_rx#228B22:%-15s" % _("Receive drops"),
172                         "VDEF:dropped_rx_min=dropped_rx,MINIMUM",
173                         "VDEF:dropped_rx_max=dropped_rx,MAXIMUM",
174                         "VDEF:dropped_rx_avg=dropped_rx,AVERAGE",
175                         "GPRINT:dropped_rx_max:%12s\: " % _("Maximum") + _("%8.0lf %spps"),
176                         "GPRINT:dropped_rx_min:%12s\: " % _("Minimum") + _("%8.0lf %spps"),
177                         "GPRINT:dropped_rx_avg:%12s\: " % _("Average") + _("%8.2lf %spps") + "\\n",
178                         "LINE1:dropped_rx#228B22",
179
180                         # Draw the transmit drops.
181                         "LINE2:dropped_tx#B22222:%-15s" % _("Transmit drops"),
182                         "VDEF:dropped_tx_min=dropped_tx,MINIMUM",
183                         "VDEF:dropped_tx_max=dropped_tx,MAXIMUM",
184                         "VDEF:dropped_tx_avg=dropped_tx,AVERAGE",
185                         "GPRINT:dropped_tx_max:%12s\: " % _("Maximum") + _("%8.0lf %spps"),
186                         "GPRINT:dropped_tx_min:%12s\: " % _("Minimum") + _("%8.0lf %spps"),
187                         "GPRINT:dropped_tx_avg:%12s\: " % _("Average") + _("%8.2lf %spps") + "\\n",
188                         "LINE1:dropped_tx#B22222",
189
190                         # Draw the collisions as a line.
191                         "LINE3:collisions#8B0000:%-15s" % _("Collisions") + "\\n",
192                 ]
193
194         @property
195         def graph_title(self):
196                 return _("Errors/dropped packets on %(interface)s")
197
198         @property
199         def graph_vertical_label(self):
200                 return _("Packets/s")
201
202
203 class InterfaceObject(base.Object):
204         rrd_schema = [
205                 "DS:bytes_rx:DERIVE:0:U",
206                 "DS:bytes_tx:DERIVE:0:U",
207                 "DS:collisions:DERIVE:0:U",
208                 "DS:dropped_rx:DERIVE:0:U",
209                 "DS:dropped_tx:DERIVE:0:U",
210                 "DS:errors_rx:DERIVE:0:U",
211                 "DS:errors_tx:DERIVE:0:U",
212                 "DS:multicast:DERIVE:0:U",
213                 "DS:packets_rx:DERIVE:0:U",
214                 "DS:packets_tx:DERIVE:0:U",
215         ]
216
217         def __repr__(self):
218                 return "<%s %s>" % (self.__class__.__name__, self.interface)
219
220         def init(self, interface):
221                 self.interface = interface
222
223         @property
224         def id(self):
225                 return self.interface
226
227         def collect(self):
228                 interface_path = os.path.join(SYS_CLASS_NET, self.interface)
229
230                 # Check if the interface exists.
231                 if not os.path.exists(interface_path):
232                         self.log.debug(_("Interface %s does not exists. Cannot collect.") \
233                                 % self.interface)
234                         return
235
236                 files = (
237                         "rx_bytes", "tx_bytes",
238                         "collisions",
239                         "rx_dropped", "tx_dropped",
240                         "rx_errors", "tx_errors",
241                         "multicast",
242                         "rx_packets", "tx_packets",
243                 )
244                 ret = []
245
246                 for file in files:
247                         path = os.path.join(interface_path, "statistics", file)
248
249                         # Open file and read it's content.
250                         f = None
251                         try:
252                                 f = open(path)
253
254                                 line = f.readline()
255                                 line = line.strip()
256                                 ret.append(line)
257                         except:
258                                 ret.append("0")
259                                 raise
260
261                         finally:
262                                 if f:
263                                         f.close()
264
265                 return ":".join(ret)
266
267
268 class InterfacePlugin(base.Plugin):
269         name = "interface"
270         description = "Interface Statistics Plugin"
271
272         templates = [
273                 GraphTemplateInterfaceBits,
274                 GraphTemplateInterfacePackets,
275                 GraphTemplateInterfaceErrors,
276         ]
277
278         interval = 20
279
280         def get_interfaces(self):
281                 for interface in os.listdir(SYS_CLASS_NET):
282                         # Skip some unwanted interfaces.
283                         if interface == "lo" or interface.startswith("mon."):
284                                 continue
285
286                         path = os.path.join(SYS_CLASS_NET, interface)
287                         if not os.path.isdir(path):
288                                 continue
289
290                         yield interface
291
292         @property
293         def objects(self):
294                 for interface in self.get_interfaces():
295                         yield InterfaceObject(self, interface=interface)