]> git.ipfire.org Git - collecty.git/blame_incremental - src/collecty/plugins/latency.py
Move color functions into the color module
[collecty.git] / src / collecty / plugins / latency.py
... / ...
CommitLineData
1#!/usr/bin/python3
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
22import socket
23
24import collecty._collecty
25from . import base
26
27from ..colours import *
28from ..i18n import _
29
30PING_HOSTS = [
31 # gateway is a special name that is automatically
32 # resolved by myhostname to the default gateway.
33 "gateway",
34
35 # The IPFire main server
36 "ping.ipfire.org",
37]
38
39class GraphTemplateLatency(base.GraphTemplate):
40 name = "latency"
41
42 lower_limit = 0
43
44 @property
45 def rrd_graph(self):
46 _ = self.locale.translate
47
48 colour_bg = AMBER
49 return [
50 # Compute the biggest loss and convert into percentage
51 "CDEF:ploss=loss6,loss4,MAX,100,*",
52
53 # Compute standard deviation
54 "CDEF:stddevarea6=stddev6,2,*",
55 "CDEF:spacer6=latency6,stddev6,-",
56 "CDEF:stddevarea4=stddev4,2,*",
57 "CDEF:spacer4=latency4,stddev4,-",
58
59 "CDEF:l005=ploss,0,5,LIMIT,UN,UNKN,INF,IF",
60 "CDEF:l010=ploss,5,10,LIMIT,UN,UNKN,INF,IF",
61 "CDEF:l025=ploss,10,25,LIMIT,UN,UNKN,INF,IF",
62 "CDEF:l050=ploss,25,50,LIMIT,UN,UNKN,INF,IF",
63 "CDEF:l099=ploss,50,99,LIMIT,UN,UNKN,INF,IF",
64
65 "LINE2:latency6_avg%s:%s" % (
66 transparency(COLOUR_IPV6, .5),
67 _("Average latency (IPv6)"),
68 ),
69 "LINE2:latency4_avg%s:%s\\r" % (
70 transparency(COLOUR_IPV4, .5),
71 _("Average latency (IPv4)"),
72 ),
73
74 "COMMENT:%s" % _("Packet Loss"),
75 "AREA:l005%s:%s" % (
76 transparency(colour_bg, .2), _("0-5%"),
77 ),
78 "AREA:l010%s:%s" % (
79 transparency(colour_bg, .4), _("5-10%"),
80 ),
81 "AREA:l025%s:%s" % (
82 transparency(colour_bg, .6), _("10-25%"),
83 ),
84 "AREA:l050%s:%s" % (
85 transparency(colour_bg, .8), _("25-50%"),
86 ),
87 "AREA:l099%s:%s\\r" % (colour_bg, _("50-99%")),
88
89 "COMMENT: \\n", # empty line
90
91 "AREA:spacer4",
92 "AREA:stddevarea4%s:STACK" % lighten(COLOUR_IPV4, STDDEV_OPACITY),
93 "LINE2:latency4%s:%s" % (COLOUR_IPV4, _("Latency (IPv4)")),
94 "GPRINT:latency4_max:%12s\:" % _("Maximum") + " %6.2lf",
95 "GPRINT:latency4_min:%12s\:" % _("Minimum") + " %6.2lf",
96 "GPRINT:latency4_avg:%12s\:" % _("Average") + " %6.2lf\\n",
97
98 "AREA:spacer6",
99 "AREA:stddevarea6%s:STACK" % lighten(COLOUR_IPV6, STDDEV_OPACITY),
100 "LINE2:latency6%s:%s" % (COLOUR_IPV6, _("Latency (IPv6)")),
101 "GPRINT:latency6_max:%12s\:" % _("Maximum") + " %6.2lf",
102 "GPRINT:latency6_min:%12s\:" % _("Minimum") + " %6.2lf",
103 "GPRINT:latency6_avg:%12s\:" % _("Average") + " %6.2lf\\n",
104 ]
105
106 @property
107 def graph_title(self):
108 _ = self.locale.translate
109
110 if self.object.hostname == "gateway":
111 hostname = _("Default Gateway")
112 else:
113 hostname = self.object.hostname
114
115 return _("Latency to %s") % hostname
116
117 @property
118 def graph_vertical_label(self):
119 _ = self.locale.translate
120 return _("Milliseconds")
121
122 @property
123 def rrd_graph_args(self):
124 return [
125 "--legend-direction=bottomup",
126 ]
127
128
129class LatencyObject(base.Object):
130 rrd_schema = [
131 "DS:latency6:GAUGE:0:U",
132 "DS:stddev6:GAUGE:0:U",
133 "DS:loss6:GAUGE:0:100",
134 "DS:latency4:GAUGE:0:U",
135 "DS:stddev4:GAUGE:0:U",
136 "DS:loss4:GAUGE:0:100",
137 ]
138
139 def __repr__(self):
140 return "<%s %s>" % (self.__class__.__name__, self.hostname)
141
142 def init(self, hostname):
143 self.hostname = hostname
144
145 @property
146 def id(self):
147 return self.hostname
148
149 def collect(self):
150 result = []
151
152 for family in (socket.AF_INET6, socket.AF_INET):
153 try:
154 p = collecty._collecty.Ping(self.hostname, family=family)
155 p.ping(count=5, deadline=10)
156
157 result += (p.average, p.stddev, p.loss)
158
159 except collecty._collecty.PingAddHostError as e:
160 self.log.debug(_("Could not add host %(host)s for family %(family)s") \
161 % { "host" : self.hostname, "family" : family })
162
163 # No data available
164 result += (None, None, None)
165 continue
166
167 except collecty._collecty.PingNoReplyError:
168 # Unknown but 100% loss
169 result += (None, None, 1)
170 continue
171
172 except collecty._collecty.PingError as e:
173 self.log.warning(_("Could not run latency check for %(host)s: %(msg)s") \
174 % { "host" : self.hostname, "msg" : e })
175
176 # A hundred percent loss
177 result += (None, None, 1)
178
179 return result
180
181
182class LatencyPlugin(base.Plugin):
183 name = "latency"
184 description = "Latency (ICMP ping) Plugin"
185
186 templates = [GraphTemplateLatency]
187
188 @property
189 def objects(self):
190 for hostname in PING_HOSTS:
191 yield LatencyObject(self, hostname)