Refactored to provide more resilience against null values and added additional signal information to the exporter

This commit is contained in:
Rob Lee 2020-04-09 21:08:30 +01:00
parent d47fe3833e
commit bfbda564cc
2 changed files with 33 additions and 45 deletions

View File

@ -63,5 +63,7 @@ Example dashboard [config](/examples/grafana.json)
Guage values taken from: https://wiki.teltonika-networks.com/view/Mobile_Signal_Strength_Recommendations Guage values taken from: https://wiki.teltonika-networks.com/view/Mobile_Signal_Strength_Recommendations
Note: Different operators appear to provide different signal information, so not all values will be available across all operators. The above dashboard works for Three, however not for Vodafonefor example.
## Todo ## Todo

View File

@ -16,57 +16,45 @@ def prom_exporter():
# Auth to router # Auth to router
conn ='http://'+os.environ.get('ROUTER_USER')+':'+os.environ.get('ROUTER_PASS')+'@'+os.environ.get('ROUTER_ADDRESS')+'/' conn ='http://'+os.environ.get('ROUTER_USER')+':'+os.environ.get('ROUTER_PASS')+'@'+os.environ.get('ROUTER_ADDRESS')+'/'
#print('Connecting to '+conn)
connection = AuthorizedConnection(conn) connection = AuthorizedConnection(conn)
# Initiatise client # Initiatise client
client = Client(connection) client = Client(connection)
pprint.pprint(client.device.signal()) # Can be accessed without authorization if os.environ.get('VERBOSE') is not None:
#pprint.pprint(client.device.information()) # Needs valid authorization, will throw exception if invalid credentials are passed in URL pprint.pprint(client.device.signal()) # Can be accessed without authorization
pprint.pprint(client.device.information()) # Needs valid authorization, will throw exception if invalid credentials are passed in URL
signal = { 'band' : client.device.signal().get('band'), # Set common response attributes
'rsrp' : client.device.signal().get('rsrp').replace("dBm", ""), band = client.device.signal().get('band')
'rsrq' : client.device.signal().get('rsrq').replace("dB", ""), device = 'deviceName="'+ client.device.information().get('DeviceName')+'",iccid="'+client.device.information().get('Iccid')+'"'
'rssi' : client.device.signal().get('rssi').replace("dBm", ""), deviceband = device
'sinr' : client.device.signal().get('sinr').replace("dB", "") if band is not None:
} devband = device+',band="'+band+'"'
dev = 'deviceName="'+ client.device.information().get('DeviceName')+'",iccid="'+client.device.information().get('Iccid')+'"'
devband=dev
if signal.get('band') is not None:
devband = dev+',band="'+signal.get('band')+'"'
# HELP ifInDiscards The number of inbound packets which were chosen to be discarded even though no errors had been detected to prevent their being deliverable to a higher-layer protocol - 1.3.6.1.2.1.2.2.1.13
# TYPE ifInDiscards counter
#ifInDiscards{ifAlias="",ifDescr="atm0",ifIndex="7",ifName=""} 81
# Retrieve attributes
signal = { 'band': { 'help': 'The signal band the LTE connection is using', 'type': 'gauge', 'device': device, 'value': band},
'rsrp': { 'help': 'The average power received from a single Reference signal in dBm', 'type': 'gauge', 'device': deviceband, 'value': client.device.signal().get('rsrp')},
'rsrq': { 'help': 'Indicates quality of the received signal in db', 'type': 'gauge', 'device': deviceband, 'value': client.device.signal().get('rsrq')},
'rssi': { 'help': 'Represents the entire received power including the wanted power from the serving cell as well as all co-channel power and other sources of noise in dBm', 'type': 'gauge', 'device': deviceband, 'value': client.device.signal().get('rssi')},
'rscp': { 'help': 'Denotes the power measured by a receiver on a particular physical communication channel in dBm', 'type': 'gauge', 'device': deviceband, 'value': client.device.signal().get('rscp')},
'sinr': { 'help': 'The signal-to-noise ratio of the given signal in dB', 'type': 'gauge', 'device': deviceband, 'value': client.device.signal().get('sinr')},
'ecio': { 'help': 'The EC/IO is a measure of the quality/cleanliness of the signal from the tower to the modem and indicates the signal-to noise ratio in dB', 'type': 'gauge', 'device': deviceband, 'value': client.device.signal().get('ecio')}
}
if os.environ.get('VERBOSE') is not None:
pprint.pprint(signal)
# Cleanse data
for attribute, info in signal.items():
if info['value'] is not None:
info['value'] = info['value'].replace("dBm", "")
info['value'] = info['value'].replace("dB", "")
# Populate response
response=[] response=[]
# Band for attribute, info in signal.items():
if signal.get('band') is not None: if attribute is not None and info['value'] is not None:
response.append('#HELP band The signal band the LTE connection is using') response.append('#HELP '+attribute+' '+info['help'])
response.append('#TYPE band gauge') response.append('#TYPE '+attribute+' '+info['type'])
response.append('band{'+dev+'} '+signal.get('band')) response.append(attribute+'{'+info['device']+'} '+info['value'])
# rsrp
if signal.get('rsrp') is not None:
response.append('#HELP rsrp The average power received from a single Reference signal, and Its typical range is around -44dbm (good) to -140dbm(bad)')
response.append('#TYPE rsrp gauge')
response.append('rsrp{'+devband+'} '+signal.get('rsrp'))
# rsrq
if signal.get('rsrq') is not None:
response.append('#HELP rsrq Indicates quality of the received signal, and its range is typically -19.5dB(bad) to -3dB (good)')
response.append('#TYPE rsrq gauge')
response.append('rsrq{'+devband+'} '+signal.get('rsrq'))
# rssi
if signal.get('rssi') is not None:
response.append('#HELP rssi Represents the entire received power including the wanted power from the serving cell as well as all co-channel power and other sources of noise in dBm')
response.append('#TYPE rssi gauge')
response.append('rssi{'+devband+'} '+signal.get('rssi'))
# sinr
if signal.get('sinr') is not None:
response.append('#HELP sinr The signal-to-noise ratio of the given signal in dB')
response.append('#TYPE sinr gauge')
response.append('sinr{'+devband+'} '+signal.get('sinr'))
s='\n' s='\n'
return s.join(response) return s.join(response)
@ -80,8 +68,6 @@ class GetHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
self.end_headers() self.end_headers()
self.wfile.write(prom_exporter().encode()) self.wfile.write(prom_exporter().encode())
Handler = GetHandler Handler = GetHandler
httpd = SocketServer.TCPServer(("", int(os.environ.get('PROM_PORT'))), Handler) httpd = SocketServer.TCPServer(("", int(os.environ.get('PROM_PORT'))), Handler)