Mercurial > ~darius > hgwebdir.cgi > adslstats
comparison adslstats.py @ 37:4f9a79f733ff
Don't explode when the link is down.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Sat, 21 Nov 2020 10:31:42 +1030 |
parents | 5dbc310f1eca |
children | 6f85bedf9966 |
comparison
equal
deleted
inserted
replaced
36:5dbc310f1eca | 37:4f9a79f733ff |
---|---|
104 rrdname = "%s.rrd" % (args.base) | 104 rrdname = "%s.rrd" % (args.base) |
105 graphbasename = args.base | 105 graphbasename = args.base |
106 | 106 |
107 class DSLStats(object): | 107 class DSLStats(object): |
108 def __str__(self): | 108 def __str__(self): |
109 if self.upstream == None: | |
110 return 'Disconnected' | |
111 | |
109 s = '''Line Rate - Up: %d kbits, Down %d kbits | 112 s = '''Line Rate - Up: %d kbits, Down %d kbits |
110 Maximum Rate - Up: %d kbit, Down %s kbit | 113 Maximum Rate - Up: %d kbit, Down %s kbit |
111 Noise Margin - Up: %.1f dB, Down %.1f dB | 114 Noise Margin - Up: %.1f dB, Down %.1f dB |
112 Attenuation - Up: %.1f dB, Down %.1f dB | 115 Attenuation - Up: %.1f dB, Down %.1f dB |
113 Power - Up: %.1f dBm, Down %.1f dBm | 116 Power - Up: %.1f dBm, Down %.1f dBm |
175 if bs.find('div', 'login') != None: | 178 if bs.find('div', 'login') != None: |
176 return False | 179 return False |
177 | 180 |
178 # Helper function to extract data | 181 # Helper function to extract data |
179 def getvals(bs, text, mult = 1): | 182 def getvals(bs, text, mult = 1): |
180 subs = bs.findAll('label', text = text)[0].fetchNextSiblings()[0].strings | 183 subs = bs.findAll('label', text = text) |
184 if len(subs) == 0: | |
185 return None, None | |
186 subs = subs[0].fetchNextSiblings()[0].strings | |
181 tmp = [float(s.split()[0]) for s in subs] | 187 tmp = [float(s.split()[0]) for s in subs] |
182 return [s * mult for s in tmp] | 188 return [s * mult for s in tmp] |
183 | 189 |
184 if list(bs.findAll('label', text = 'DSL Status')[0].fetchNextSiblings()[0].strings)[0] == 'Up': | 190 tmp = bs.findAll('label', text = 'DSL Status') |
191 if len(tmp) > 0 and list(tmp[0].fetchNextSiblings()[0].strings)[0] == 'Up': | |
185 stats.linkup = True | 192 stats.linkup = True |
186 else: | 193 else: |
187 stats.linkup = False | 194 stats.linkup = False |
188 | 195 |
189 stats.upstreammax, stats.downstreammax = getvals(bs, 'Maximum Line rate', 1e3) | 196 stats.upstreammax, stats.downstreammax = getvals(bs, 'Maximum Line rate', 1e3) |
190 stats.upstream, stats.downstream = getvals(bs, 'Line Rate', 1e3) | 197 stats.upstream, stats.downstream = getvals(bs, 'Line Rate', 1e3) |
191 stats.uppower, stats.downpower = getvals(bs, 'Output Power') | 198 stats.uppower, stats.downpower = getvals(bs, 'Output Power') |
192 stats.nmup, stats.nmdown = getvals(bs, 'Noise Margin') | 199 stats.nmup, stats.nmdown = getvals(bs, 'Noise Margin') |
193 | 200 |
194 # Line attenuation returns several values for each direction, parse specially and just take the first one | 201 # Line attenuation returns several values for each direction, parse specially and just take the first one |
195 upattens, downattens = list(bs.findAll('label', text = 'Line Attenuation')[0].fetchNextSiblings()[0].strings) | 202 tmp = bs.findAll('label', text = 'Line Attenuation') |
196 stats.attenup = float(re.findall('([0-9.N/A]+)', upattens)[0]) | 203 if len(tmp) == 0: |
197 stats.attendown = float(re.findall('([0-9.N/A]+)', downattens)[0]) | 204 stats.attenup, stats.attendown = None, None |
205 else: | |
206 upattens, downattens = list(tmp[0].fetchNextSiblings()[0].strings) | |
207 stats.attenup = float(re.findall('([0-9.N/A]+)', upattens)[0]) | |
208 stats.attendown = float(re.findall('([0-9.N/A]+)', downattens)[0]) | |
198 | 209 |
199 # Convert something like '2days 17hours 28min 19sec' into seconds | 210 # Convert something like '2days 17hours 28min 19sec' into seconds |
200 uptime = re.findall('([0-9]+)', list(bs.findAll('label', text = 'DSL Uptime')[0].fetchNextSiblings()[0].strings)[0]) | 211 tmp = bs.findAll('label', text = 'DSL Uptime') |
201 uptime.reverse() # End up with an array of seconds, minutes, hours, etc | 212 if len(tmp) == 0: |
202 mults = [1, 60, 60 * 60, 24 * 60 * 60] | |
203 # Basic sanity check of the number of elements, should be at least 1 | |
204 if len(uptime) == 0 or len(uptime) > len(mults): | |
205 print('Unexpected number of uptime elements (%s)' % str(uptime)) | |
206 stats.uptime = None | 213 stats.uptime = None |
207 else: | 214 else: |
208 stats.uptime = reduce(lambda a, b: a + b, [int(a[0]) * a[1] for a in zip(uptime, mults)]) | 215 uptime = re.findall('([0-9]+)', list(tmp[0].fetchNextSiblings()[0].strings)[0]) |
216 uptime.reverse() # End up with an array of seconds, minutes, hours, etc | |
217 mults = [1, 60, 60 * 60, 24 * 60 * 60] | |
218 # Basic sanity check of the number of elements, should be at least 1 | |
219 if len(uptime) == 0 or len(uptime) > len(mults): | |
220 print('Unexpected number of uptime elements (%s)' % str(uptime)) | |
221 stats.uptime = None | |
222 else: | |
223 stats.uptime = reduce(lambda a, b: a + b, [int(a[0]) * a[1] for a in zip(uptime, mults)]) | |
209 | 224 |
210 return True | 225 return True |
211 | 226 |
212 # Setup RRD | 227 # Setup RRD |
213 # We expect data to be logged every 5 minutes | 228 # We expect data to be logged every 5 minutes |
235 'RRA:MIN:0.1:12:168', | 250 'RRA:MIN:0.1:12:168', |
236 'RRA:MAX:0.1:12:168') | 251 'RRA:MAX:0.1:12:168') |
237 | 252 |
238 # Update the RRD (format stats as expected) | 253 # Update the RRD (format stats as expected) |
239 def updaterrd(filename, tstamp, stats): | 254 def updaterrd(filename, tstamp, stats): |
255 if stats.uptime == None: | |
256 return | |
240 rrdtool.update(filename, | 257 rrdtool.update(filename, |
241 '%d:%d:%d:%d:%d:%f:%f:%f:%f:U:U:%f:%f:%d' % ( | 258 '%d:%d:%d:%d:%d:%f:%f:%f:%f:U:U:%f:%f:%d' % ( |
242 tstamp, | 259 tstamp, |
243 stats.upstream, | 260 stats.upstream, |
244 stats.downstream, | 261 stats.downstream, |