summaryrefslogtreecommitdiff
path: root/overlays/zte-prometheus-exporter
diff options
context:
space:
mode:
Diffstat (limited to 'overlays/zte-prometheus-exporter')
-rw-r--r--overlays/zte-prometheus-exporter/default.nix13
-rw-r--r--overlays/zte-prometheus-exporter/zte-prometheus-exporter.py90
2 files changed, 62 insertions, 41 deletions
diff --git a/overlays/zte-prometheus-exporter/default.nix b/overlays/zte-prometheus-exporter/default.nix
index 2188e7b3..6295567d 100644
--- a/overlays/zte-prometheus-exporter/default.nix
+++ b/overlays/zte-prometheus-exporter/default.nix
@@ -1,18 +1,17 @@
1{ final, prev, ... }: 1{ final, prev, ... }:
2let 2let
3 packageOverrides = final.callPackage ./python-packages.nix {}; 3 packageOverrides = final.callPackage ./python-packages.nix {};
4 inpPython = final.python310.override { inherit packageOverrides; }; 4 inpPython = final.python3.override { inherit packageOverrides; };
5 python = inpPython.withPackages (ps: with ps; [pytimeparse requests]);
5in { 6in {
6 zte-prometheus-exporter = prev.stdenv.mkDerivation rec { 7 zte-prometheus-exporter = prev.stdenv.mkDerivation rec {
7 name = "zte-prometheus-exporter"; 8 name = "zte-prometheus-exporter";
8 src = ./zte-prometheus-exporter.py; 9 src = prev.replaceVars ./zte-prometheus-exporter.py { inherit python; };
9 10
10 phases = [ "buildPhase" "checkPhase" "installPhase" ]; 11 phases = [ "unpackPhase" "checkPhase" "installPhase" ];
11 12
12 python = inpPython.withPackages (ps: with ps; [pytimeparse requests]); 13 unpackPhase = ''
13 14 cp $src zte-prometheus-exporter
14 buildPhase = ''
15 substituteAll $src zte-prometheus-exporter
16 ''; 15 '';
17 16
18 doCheck = true; 17 doCheck = true;
diff --git a/overlays/zte-prometheus-exporter/zte-prometheus-exporter.py b/overlays/zte-prometheus-exporter/zte-prometheus-exporter.py
index fc719a96..1d150eda 100644
--- a/overlays/zte-prometheus-exporter/zte-prometheus-exporter.py
+++ b/overlays/zte-prometheus-exporter/zte-prometheus-exporter.py
@@ -54,13 +54,13 @@ class ZTEMetrics:
54 cls._instance.password = environ.get('ZTE_PASSWORD') 54 cls._instance.password = environ.get('ZTE_PASSWORD')
55 cls._instance.attrs = None 55 cls._instance.attrs = None
56 return cls._instance 56 return cls._instance
57 57
58 58
59 def __init__(self): 59 def __init__(self):
60 raise RuntimeError('Call instance() instead') 60 raise RuntimeError('Call instance() instead')
61 61
62 _error_pattern = re.compile('^IF_ERROR(PARAM|TYPE|STR|ID)$') 62 _error_pattern = re.compile(r'^IF_ERROR(PARAM|TYPE|STR|ID)$')
63 _obj_pattern = re.compile('^(?:OBJ_(.+)_ID)|(?:ID_(WAN_COMFIG))$') 63 _obj_pattern = re.compile(r'^(?:OBJ_(.+)_ID)|(?:ID_(WAN_COMFIG))$')
64 def update(self): 64 def update(self):
65 attrs = dict() 65 attrs = dict()
66 66
@@ -106,6 +106,8 @@ class ZTEMetrics:
106 value = child.text 106 value = child.text
107 case _: 107 case _:
108 pass 108 pass
109 if value == '0,0':
110 value = '0'
109 if not name is None and not value is None: 111 if not name is None and not value is None:
110 instance_dict[name] = value 112 instance_dict[name] = value
111 name = None 113 name = None
@@ -120,11 +122,21 @@ class ZTEMetrics:
120 def json_text(self): 122 def json_text(self):
121 return json.dumps(self.attrs) 123 return json.dumps(self.attrs)
122 124
123 _link_pattern = re.compile('^IGD\.WD1\.LINE([0-9]+)$') 125 _link_pattern = re.compile(r'^IGD\.WD1\.LINE([0-9]+)$')
124 _eth_pattern = re.compile('^IGD\.LD1\.ETH([0-9]+)$') 126 _eth_pattern = re.compile(r'^IGD\.LD1\.ETH([0-9]+)$')
125 def prometheus(self): 127 def prometheus(self):
126 metrics = '' 128 metrics = ''
127 129
130 metrics += _format_prom_metrics('info', 'gauge', [({
131 "version_date": self.attrs['DEVINFO']['IGD']['VerDate'],
132 "software_version": self.attrs['DEVINFO']['IGD']['SoftwareVer'],
133 "model_name": self.attrs['DEVINFO']['IGD']['ModelName'],
134 "model_firmware_version": self.attrs['DEVINFO']['IGD']['ModelFirmwareVer'],
135 "hardware_version": self.attrs['DEVINFO']['IGD']['HardwareVer'],
136 "serial_number": self.attrs['DEVINFO']['IGD']['SerialNumber'],
137 "boot_version": self.attrs['DEVINFO']['IGD']['BootVer'],
138 }, 1)], 'Metadata about a given ZTE device')
139
128 uptime_seconds = timeparse(self.attrs['SYSTEMYIME']['IGD']['systemTime']) 140 uptime_seconds = timeparse(self.attrs['SYSTEMYIME']['IGD']['systemTime'])
129 metrics += _format_prom_metrics('uptime_seconds', 'gauge', [({}, uptime_seconds)], 'Seconds device has been running') 141 metrics += _format_prom_metrics('uptime_seconds', 'gauge', [({}, uptime_seconds)], 'Seconds device has been running')
130 142
@@ -133,34 +145,44 @@ class ZTEMetrics:
133 link_match = self._link_pattern.match(link) 145 link_match = self._link_pattern.match(link)
134 link_number = link_match.group(1) 146 link_number = link_match.group(1)
135 147
136 if 'crc_errors_count' not in link_metrics: 148 link_is_up = self.attrs['DSLINTERFACE'][link]['Status'] == 'Up'
137 link_metrics['crc_errors_count'] = {'type': 'counter', 'metrics': []} 149
138 link_metrics['crc_errors_count']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['UpCrc_errors']))] 150 if link_is_up:
139 link_metrics['crc_errors_count']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['DownCrc_errors']))] 151 if 'crc_errors_count' not in link_metrics:
140 152 link_metrics['crc_errors_count'] = {'type': 'counter', 'metrics': []}
141 if 'noise_margin_db' not in link_metrics: 153 link_metrics['crc_errors_count']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['UpCrc_errors']))]
142 link_metrics['noise_margin_db'] = {'type': 'gauge', 'metrics': []} 154 link_metrics['crc_errors_count']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['DownCrc_errors']))]
143 link_metrics['noise_margin_db']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_noise_margin']))] 155
144 link_metrics['noise_margin_db']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_noise_margin']))] 156 if 'noise_margin_db' not in link_metrics:
145 157 link_metrics['noise_margin_db'] = {'type': 'gauge', 'metrics': []}
146 if 'attenuation_db' not in link_metrics: 158 link_metrics['noise_margin_db']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_noise_margin']) / 10)]
147 link_metrics['attenuation_db'] = {'type': 'gauge', 'metrics': []} 159 link_metrics['noise_margin_db']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_noise_margin']) / 10)]
148 link_metrics['attenuation_db']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_attenuation']))] 160
149 link_metrics['attenuation_db']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_attenuation']))] 161 if 'attenuation_db' not in link_metrics:
150 162 link_metrics['attenuation_db'] = {'type': 'gauge', 'metrics': []}
151 if 'max_rate_kbps' not in link_metrics: 163 link_metrics['attenuation_db']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_attenuation']) / 10)]
152 link_metrics['max_rate_kbps'] = {'type': 'gauge', 'metrics': []} 164 link_metrics['attenuation_db']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_attenuation']) / 10)]
153 link_metrics['max_rate_kbps']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_max_rate']))] 165
154 link_metrics['max_rate_kbps']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_max_rate']))] 166 if 'max_rate_kbps' not in link_metrics:
155 167 link_metrics['max_rate_kbps'] = {'type': 'gauge', 'metrics': []}
156 if 'current_rate_kbps' not in link_metrics: 168 link_metrics['max_rate_kbps']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_max_rate']))]
157 link_metrics['current_rate_kbps'] = {'type': 'gauge', 'metrics': []} 169 link_metrics['max_rate_kbps']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_max_rate']))]
158 link_metrics['current_rate_kbps']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_current_rate']))] 170
159 link_metrics['current_rate_kbps']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_current_rate']))] 171 if 'current_rate_kbps' not in link_metrics:
160 172 link_metrics['current_rate_kbps'] = {'type': 'gauge', 'metrics': []}
161 if 'dsl_uptime_seconds' not in link_metrics: 173 link_metrics['current_rate_kbps']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_current_rate']))]
162 link_metrics['dsl_uptime_seconds'] = {'type': 'gauge', 'metrics': []} 174 link_metrics['current_rate_kbps']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_current_rate']))]
163 link_metrics['dsl_uptime_seconds']['metrics'] += [({"link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Showtime_start']))] 175
176 if 'uptime_seconds' not in link_metrics:
177 link_metrics['uptime_seconds'] = {'type': 'gauge', 'metrics': []}
178 link_metrics['uptime_seconds']['metrics'] += [({"link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Showtime_start']) if link_is_up else 0)]
179
180 if 'status' not in link_metrics:
181 link_metrics['status'] = {'type': 'gauge', 'metrics': []}
182 up_status, *status = self.attrs['DSLINTERFACE'][link]['Status'].split(',')
183 down_status = up_status if not status else status[0]
184 link_metrics['status']['metrics'] += [({"link": link_number, "direction": "up", "status": up_status}, 1)]
185 link_metrics['status']['metrics'] += [({"link": link_number, "direction": "down", "status": down_status}, 1)]
164 if link_metrics: 186 if link_metrics:
165 for metric_name in link_metrics: 187 for metric_name in link_metrics:
166 metrics += _format_prom_metrics(f'dsl_{metric_name}', link_metrics[metric_name]['type'], link_metrics[metric_name]['metrics']) 188 metrics += _format_prom_metrics(f'dsl_{metric_name}', link_metrics[metric_name]['type'], link_metrics[metric_name]['metrics'])
@@ -203,7 +225,7 @@ class ZTEMetricsServer(BaseHTTPRequestHandler):
203 self.send_response(200) 225 self.send_response(200)
204 self.send_header("Content-type", "text/plain") 226 self.send_header("Content-type", "text/plain")
205 self.end_headers() 227 self.end_headers()
206 228
207 self.wfile.write(zte_metrics.prometheus()) 229 self.wfile.write(zte_metrics.prometheus())
208 case _: 230 case _:
209 self.send_response(404) 231 self.send_response(404)