Mercurial > ~darius > hgwebdir.cgi > adslstats
comparison adslstats.py @ 18:ec994073f70a
Gather more stats (not plotted yet).
Remove some old modem cruft.
Rearrange graphs by item being graphed.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Sun, 22 May 2016 15:39:51 +0930 |
parents | 43f54da8baf9 |
children | 5bec78c876db |
comparison
equal
deleted
inserted
replaced
17:43f54da8baf9 | 18:ec994073f70a |
---|---|
72 opts.add_option('-b', '--base', action="store", default="/home/darius/projects/adslstats/adslstats", | 72 opts.add_option('-b', '--base', action="store", default="/home/darius/projects/adslstats/adslstats", |
73 help="Base directory for RRD & PNGs") | 73 help="Base directory for RRD & PNGs") |
74 | 74 |
75 (options, args) = opts.parse_args() | 75 (options, args) = opts.parse_args() |
76 | 76 |
77 statsurl = "http://%s/statsadsl.html" % (options.name) | |
78 rrdname = "%s.rrd" % (options.base) | 77 rrdname = "%s.rrd" % (options.base) |
79 graphbasename = options.base | 78 graphbasename = options.base |
80 | 79 |
81 matchnum = re.compile('([0-9]+(\.[0-9]+)?)') | |
82 statsdict = { | |
83 3 : 'Status:', | |
84 8 : 'SNR Margin (0.1 dB):', | |
85 9 : 'Attenuation (0.1 dB):', | |
86 14 : 'Rate (Kbps):', | |
87 } | |
88 | |
89 class DSLStats(object): | 80 class DSLStats(object): |
90 def __str__(self): | 81 def __str__(self): |
91 s = "Line Rate - Up: %d kbits, Down %d kbits\n" % (self.upstream, self.downstream) | 82 s = '''Line Rate - Up: %d kbits, Down %d kbits |
92 if hasattr(self, 'upstreammax'): | 83 Maximum Rate - Up: %d kbit, Down %s kbit |
93 s += "Maximum Rate - Up: %d kbit, Down %s kbit\n" % (self.upstreammax, self.downstreammax) | 84 Noise Margin - Up: %.1f dB, Down %.1f dB |
94 s += """Noise Margin - Up: %.1f dB, Down %.1f dB | 85 Attenuation - Up: %.1f dB, Down %.1f dB |
95 Attenuation - Up: %.1f dB, Down %.1f dB""" % (self.nmup, self.nmdown, | 86 Errors - Up: %d, Down %d |
96 self.attenup, self.attendown) | 87 Power - Up: %.1f dBm, Down %.1f dBm |
88 Uptime - %d sec''' % (self.upstream, self.downstream, | |
89 self.upstreammax, self.downstreammax, | |
90 self.nmup, self.nmdown, | |
91 self.attenup, self.attendown, | |
92 self.fecATUC, self.fecATUR, | |
93 self.uppower, self.downpower, | |
94 self.uptime) | |
97 return s | 95 return s |
98 | 96 |
99 def getstats(): | 97 def getstats(): |
100 stats = DSLStats() | 98 stats = DSLStats() |
101 parser = ConfigParser.ConfigParser() | 99 parser = ConfigParser.ConfigParser() |
102 base = 'http://%s' % (conf.get('global', 'name')) | 100 base = 'http://%s' % (conf.get('global', 'name')) |
103 # Gunk extracted from Chrome (what the page is requesting). Note it's sensitive to line ending type... | 101 # Gunk extracted from Chrome (what the page is requesting). Note it's sensitive to line ending type... |
104 # We could get more data, eg error rates.. | 102 # Plus information from http://forum.kitz.co.uk/index.php?topic=15738.0 |
105 data = '[WAN_DSL_INTF_CFG#1,0,0,0,0,0#0,0,0,0,0,0]0,12\r\nstatus\r\nmodulationType\r\nX_TP_AdslModulationCfg\r\nupstreamCurrRate\r\ndownstreamCurrRate\r\nX_TP_AnnexType\r\nupstreamMaxRate\r\ndownstreamMaxRate\r\nupstreamNoiseMargin\r\ndownstreamNoiseMargin\r\nupstreamAttenuation\r\ndownstreamAttenuation\r\n[WAN_DSL_INTF_STATS_TOTAL#1,0,0,0,0,0#0,0,0,0,0,0]1,8\r\nATUCCRCErrors\r\nCRCErrors\r\nATUCFECErrors\r\nFECErrors\r\nSeverelyErroredSecs\r\nX_TP_US_SeverelyErroredSecs\r\nerroredSecs\r\nX_TP_US_ErroredSecs\r\n' | 103 # ATUR = ADSL Termination Unit Remote |
104 # ATUC = ADSL Termination Unit Central office | |
105 query = '[WAN_DSL_INTF_CFG#0,0,0,0,0,0#0,0,0,0,0,0]0,0\r\n[WAN_DSL_INTF_STATS_TOTAL#0,0,0,0,0,0#0,0,0,0,0,0]1,0\r\n' | |
106 cookies = {'Authorization' : 'Basic ' + base64.standard_b64encode(conf.get('global', 'username') + ':' + conf.get('global', 'password'))} | 106 cookies = {'Authorization' : 'Basic ' + base64.standard_b64encode(conf.get('global', 'username') + ':' + conf.get('global', 'password'))} |
107 headers = {'Referer' : base} | 107 headers = {'Referer' : base} |
108 r = requests.post(base + '/cgi?1&5' , data = data, headers = headers, cookies = cookies, stream = True) | 108 r = requests.post(base + '/cgi?5&5' , data = query, headers = headers, cookies = cookies, stream = True) |
109 parser.readfp(r.raw) | 109 parser.readfp(r.raw) |
110 res = {} | 110 res = {} |
111 tmp = '1,0,0,0,0,0' | 111 tmp = '1,0,0,0,0,0' |
112 if parser.get(tmp, 'status') == 'Up': | 112 if parser.get(tmp, 'status') == 'Up': |
113 stats.linkup = True | 113 stats.linkup = True |
119 stats.downstreammax = float(parser.get(tmp, 'downstreamMaxRate')) | 119 stats.downstreammax = float(parser.get(tmp, 'downstreamMaxRate')) |
120 stats.nmup = float(parser.get(tmp, 'upstreamNoiseMargin')) / 10.0 | 120 stats.nmup = float(parser.get(tmp, 'upstreamNoiseMargin')) / 10.0 |
121 stats.nmdown = float(parser.get(tmp, 'downstreamNoiseMargin')) / 10.0 | 121 stats.nmdown = float(parser.get(tmp, 'downstreamNoiseMargin')) / 10.0 |
122 stats.attenup = float(parser.get(tmp, 'upstreamAttenuation')) / 10.0 | 122 stats.attenup = float(parser.get(tmp, 'upstreamAttenuation')) / 10.0 |
123 stats.attendown = float(parser.get(tmp, 'downstreamAttenuation')) / 10.0 | 123 stats.attendown = float(parser.get(tmp, 'downstreamAttenuation')) / 10.0 |
124 stats.fecATUR = int(parser.get(tmp, 'FECErrors')) | |
125 stats.fecATUC = int(parser.get(tmp, 'ATUCFECErrors')) | |
126 stats.uppower = float(parser.get(tmp, 'upstreamPower')) / 10.0 # I think it's tenths of a dBm but who knows | |
127 stats.downpower = float(parser.get(tmp, 'downstreamPower')) / 10.0 | |
128 stats.uptime = int(parser.get(tmp, 'showtimeStart')) | |
124 | 129 |
125 return stats | 130 return stats |
126 | 131 |
127 # Setup RRD | 132 # Setup RRD |
128 # We expect data to be logged every 5 minutes | 133 # We expect data to be logged every 5 minutes |
138 'DS:downstreammax:GAUGE:3600:32:150000', # Downstream maximum (kbits) | 143 'DS:downstreammax:GAUGE:3600:32:150000', # Downstream maximum (kbits) |
139 'DS:nmup:GAUGE:3600:0:100', # Upstream Noise margin (dB) | 144 'DS:nmup:GAUGE:3600:0:100', # Upstream Noise margin (dB) |
140 'DS:nmdown:GAUGE:3600:0:100', # Downstream Noise margin (dB) | 145 'DS:nmdown:GAUGE:3600:0:100', # Downstream Noise margin (dB) |
141 'DS:attenup:GAUGE:3600:0:100', # Upstream Attenuation (dB) | 146 'DS:attenup:GAUGE:3600:0:100', # Upstream Attenuation (dB) |
142 'DS:attendown:GAUGE:3600:0:100', # Downstream Attenuation (dB) | 147 'DS:attendown:GAUGE:3600:0:100', # Downstream Attenuation (dB) |
148 'DS:fecATUC:DERIVE:3600:0:U', # Upstream FEC error count | |
149 'DS:fecATUR:DERIVE:3600:0:U', # Downstream FEC error count | |
150 'DS:powerup:GAUGE:3600:-100:100', # Upstream Power (dBm) | |
151 'DS:powerdown:GAUGE:3600:-100:100', # Downstream Power (dBm) | |
152 'DS:uptime:DERIVE:3600:0:U', # Uptime (seconds) | |
143 'RRA:AVERAGE:0.1:12:168', | 153 'RRA:AVERAGE:0.1:12:168', |
144 'RRA:AVERAGE:0.1:288:1825', | 154 'RRA:AVERAGE:0.1:288:1825', |
145 'RRA:MIN:0.1:12:168', | 155 'RRA:MIN:0.1:12:168', |
146 'RRA:MAX:0.1:12:168') | 156 'RRA:MAX:0.1:12:168') |
147 | 157 |
148 # Update the RRD (format stats as expected) | 158 # Update the RRD (format stats as expected) |
149 def updaterrd(filename, tstamp, stats): | 159 def updaterrd(filename, tstamp, stats): |
150 rrdtool.update(filename, | 160 rrdtool.update(filename, |
151 '%d:%d:%d:%d:%d:%f:%f:%f:%f' % (tstamp, | 161 '%d:%d:%d:%d:%d:%f:%f:%f:%f:%d:%d:%f:%f:%d' % ( |
152 stats.upstream, | 162 tstamp, |
153 stats.downstream, | 163 stats.upstream, |
154 stats.upstreammax, | 164 stats.downstream, |
155 stats.downstreammax, | 165 stats.upstreammax, |
156 stats.nmup, | 166 stats.downstreammax, |
157 stats.nmdown, | 167 stats.nmup, |
158 stats.attenup, | 168 stats.nmdown, |
159 stats.attendown)) | 169 stats.attenup, |
170 stats.attendown, | |
171 stats.fecATUC, | |
172 stats.fecATUR, | |
173 stats.uppower, | |
174 stats.downpower, | |
175 stats.uptime)) | |
160 | 176 |
161 # Open the URL and call the parser | 177 # Open the URL and call the parser |
162 def getdata(): | 178 def getdata(): |
163 stats = getstats() | 179 stats = getstats() |
164 return stats | 180 return stats |
174 '--slope-mode', | 190 '--slope-mode', |
175 | 191 |
176 'DEF:upstream=%s:upstream:AVERAGE' % rrdname, | 192 'DEF:upstream=%s:upstream:AVERAGE' % rrdname, |
177 'DEF:upstreammin=%s:upstream:MIN' % rrdname, | 193 'DEF:upstreammin=%s:upstream:MIN' % rrdname, |
178 'DEF:upstreammax=%s:upstream:MAX' % rrdname, | 194 'DEF:upstreammax=%s:upstream:MAX' % rrdname, |
195 'CDEF:upstreamdif=upstreammax,upstreammin,-', | |
196 'DEF:maxupstream=%s:upstreammax:AVERAGE' % rrdname, | |
197 | |
198 'LINE0:upstreammin#000000:', | |
199 'AREA:upstreamdif#00dc76::STACK', | |
200 'LINE1:upstream#00ff00:Upstream', | |
201 | |
202 'LINE1:maxupstream#0000ff:Upstream (maximum)', | |
179 | 203 |
180 'DEF:downstream=%s:downstream:AVERAGE' % rrdname, | 204 'DEF:downstream=%s:downstream:AVERAGE' % rrdname, |
181 'DEF:downstreammin=%s:downstream:MIN' % rrdname, | 205 'DEF:downstreammin=%s:downstream:MIN' % rrdname, |
182 'DEF:downstreammax=%s:downstream:MAX' % rrdname, | 206 'DEF:downstreammax=%s:downstream:MAX' % rrdname, |
183 | |
184 'CDEF:upstreamdif=upstreammax,upstreammin,-', | |
185 'CDEF:downstreamdif=downstreammax,downstreammin,-', | 207 'CDEF:downstreamdif=downstreammax,downstreammin,-', |
186 | |
187 'DEF:maxupstream=%s:upstreammax:AVERAGE' % rrdname, | |
188 'DEF:maxdownstream=%s:downstreammax:AVERAGE' % rrdname, | 208 'DEF:maxdownstream=%s:downstreammax:AVERAGE' % rrdname, |
189 | |
190 'LINE0:upstreammin#000000:', | |
191 'AREA:upstreamdif#00dc76::STACK', | |
192 'LINE1:upstream#00ff00:Upstream', | |
193 | 209 |
194 'LINE0:downstreammin#000000:', | 210 'LINE0:downstreammin#000000:', |
195 'AREA:downstreamdif#ff8686::STACK', | 211 'AREA:downstreamdif#ff8686::STACK', |
196 'LINE1:downstream#ff0000:Downstream', | 212 'LINE1:downstream#ff0000:Downstream', |
197 | 213 |
198 'LINE1:maxupstream#0000ff:Upstream (maximum)', | |
199 'LINE1:maxdownstream#000000:Downstream (maximum)' | 214 'LINE1:maxdownstream#000000:Downstream (maximum)' |
200 ) | 215 ) |
201 | 216 |
202 signalargs = ( | 217 signalargs = ( |
203 '-a', 'SVG', | 218 '-a', 'SVG', |
204 '--vertical-label', 'dB', | 219 '--vertical-label', 'dB', |
205 '--slope-mode', | 220 '--slope-mode', |
206 '-l', '0', | 221 '-l', '0', |
207 | 222 |
208 'DEF:upstream=%s:upstream:AVERAGE' % rrdname, | |
209 'DEF:downstream=%s:downstream:AVERAGE' % rrdname, | |
210 | |
211 'DEF:nmup_=%s:nmup:AVERAGE' % rrdname, | 223 'DEF:nmup_=%s:nmup:AVERAGE' % rrdname, |
212 'DEF:nmupmin_=%s:nmup:MIN' % rrdname, | 224 'DEF:nmupmin_=%s:nmup:MIN' % rrdname, |
213 'DEF:nmupmax_=%s:nmup:MAX' % rrdname, | 225 'DEF:nmupmax_=%s:nmup:MAX' % rrdname, |
214 | |
215 'DEF:nmdown_=%s:nmdown:AVERAGE' % rrdname, | |
216 'DEF:nmdownmin_=%s:nmdown:MIN' % rrdname, | |
217 'DEF:nmdownmax_=%s:nmdown:MAX' % rrdname, | |
218 | |
219 'DEF:attenup=%s:attenup:AVERAGE' % rrdname, | |
220 'DEF:attenupmin=%s:attenup:MIN' % rrdname, | |
221 'DEF:attenupmax=%s:attenup:MAX' % rrdname, | |
222 | |
223 'DEF:attendown=%s:attendown:AVERAGE' % rrdname, | |
224 'DEF:attendownmin=%s:attendown:MIN' % rrdname, | |
225 'DEF:attendownmax=%s:attendown:MAX' % rrdname, | |
226 | 226 |
227 'CDEF:nmup=nmup_,10,*', | 227 'CDEF:nmup=nmup_,10,*', |
228 'CDEF:nmupmin=nmupmin_,10,*', | 228 'CDEF:nmupmin=nmupmin_,10,*', |
229 'CDEF:nmupmax=nmupmax_,10,*', | 229 'CDEF:nmupmax=nmupmax_,10,*', |
230 'CDEF:nmupdif=nmupmax,nmupmin,-', | 230 'CDEF:nmupdif=nmupmax,nmupmin,-', |
231 | 231 |
232 'LINE0:nmupmin#000000:', | |
233 'AREA:nmupdif#5c5cff::STACK', | |
234 'LINE1:nmup#0000ff:Noise Margin - Up (1/10 dB)', | |
235 | |
236 'DEF:nmdown_=%s:nmdown:AVERAGE' % rrdname, | |
237 'DEF:nmdownmin_=%s:nmdown:MIN' % rrdname, | |
238 'DEF:nmdownmax_=%s:nmdown:MAX' % rrdname, | |
239 | |
232 'CDEF:nmdown=nmdown_,10,*', | 240 'CDEF:nmdown=nmdown_,10,*', |
233 'CDEF:nmdownmin=nmdownmin_,10,*', | 241 'CDEF:nmdownmin=nmdownmin_,10,*', |
234 'CDEF:nmdownmax=nmdownmax_,10,*', | 242 'CDEF:nmdownmax=nmdownmax_,10,*', |
235 'CDEF:nmdowndif=nmdownmax,nmdownmin,-', | 243 'CDEF:nmdowndif=nmdownmax,nmdownmin,-', |
236 | 244 |
245 'DEF:attenup=%s:attenup:AVERAGE' % rrdname, | |
246 'DEF:attenupmin=%s:attenup:MIN' % rrdname, | |
247 'DEF:attenupmax=%s:attenup:MAX' % rrdname, | |
248 | |
237 'CDEF:attenupdif=attenupmax,attenupmin,-', | 249 'CDEF:attenupdif=attenupmax,attenupmin,-', |
238 | 250 |
251 'DEF:attendown=%s:attendown:AVERAGE' % rrdname, | |
252 'DEF:attendownmin=%s:attendown:MIN' % rrdname, | |
253 'DEF:attendownmax=%s:attendown:MAX' % rrdname, | |
254 | |
239 'CDEF:attendowndif=attendownmax,attendownmin,-', | 255 'CDEF:attendowndif=attendownmax,attendownmin,-', |
240 | 256 |
241 'LINE0:nmupmin#000000:', | 257 'DEF:powerup_=%s:powerup:AVERAGE' % rrdname, |
242 'AREA:nmupdif#5c5cff::STACK', | 258 'DEF:powerupmin_=%s:powerup:MIN' % rrdname, |
243 'LINE1:nmup#0000ff:Noise Margin - Up (1/10 dB)', | 259 'DEF:powerupmax_=%s:powerup:MAX' % rrdname, |
260 | |
261 'DEF:powerdown_=%s:powerdown:AVERAGE' % rrdname, | |
262 'DEF:powerdownmin_=%s:powerdown:MIN' % rrdname, | |
263 'DEF:powerdownmax_=%s:powerdown:MAX' % rrdname, | |
264 | |
244 | 265 |
245 'LINE0:nmdownmin#000000:', | 266 'LINE0:nmdownmin#000000:', |
246 'AREA:nmdowndif#009a00::STACK', | 267 'AREA:nmdowndif#009a00::STACK', |
247 'LINE1:nmdown#00ff00:Noise Margin - Down (1/10 dB)', | 268 'LINE1:nmdown#00ff00:Noise Margin - Down (1/10 dB)', |
248 | 269 |
317 up.min 0 | 338 up.min 0 |
318 down.label Down | 339 down.label Down |
319 down.type GAUGE | 340 down.type GAUGE |
320 down.max 15000 | 341 down.max 15000 |
321 down.min 0 | 342 down.min 0 |
322 upmax.label Up | 343 upmax.label Up (max) |
323 upmax.type GAUGE | 344 upmax.type GAUGE |
324 upmax.max 150000 | 345 upmax.max 150000 |
325 upmax.min 0 | 346 upmax.min 0 |
326 downmax.label Down | 347 downmax.label Down (max) |
327 downmax.type GAUGE | 348 downmax.type GAUGE |
328 downmax.max 150000 | 349 downmax.max 150000 |
329 downmax.min 0''' | 350 downmax.min 0''' |
330 sys.exit(0) | 351 sys.exit(0) |
331 if options.update or options.munin: | 352 if options.update or options.munin: |