This commit is contained in:
w1kl4s 2022-07-16 18:27:05 +02:00
parent b2105df1ac
commit a306198c5a
Signed by: w1kl4s
GPG Key ID: 7C5B542C41DCE7AE
5 changed files with 73 additions and 45 deletions

View File

@ -1,2 +1,2 @@
[bdist_wheel]
universal=0
universal = 0

View File

@ -1,4 +1,5 @@
from setuptools import setup, find_packages
# To use a consistent encoding
from codecs import open
from os import path
@ -11,35 +12,23 @@ with open(path.join(here, "README.md"), encoding="utf-8") as f:
setup(
name="radio_exporter",
version='0.1.0',
version="0.1.0",
description="",
long_description=long_description,
url="https://git.gammaspectra.live/S.O.N.G/radio_exporter",
author="w1kl4s",
author_email="w1kl4s@protonmail.com",
license="BSD 2-Clause",
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: System Administrators",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
],
python_requires=">=3.6, <4",
keywords="monitoring metrics exporter radio",
packages=["src"],
install_requires=[
"requests"
],
entry_points={
"console_scripts": ["radio_exporter=src.main:start"]
}
install_requires=["requests"],
entry_points={"console_scripts": ["radio_exporter=src.main:start"]},
)

View File

@ -5,26 +5,32 @@ import requests
from collections.abc import MutableMapping
from dataclasses import dataclass
@dataclass
class Metric:
prefix: str
value_name: str
labels: dict
value: int
value: int
def format_prom(self) -> str:
labels = ','.join(x + '=' + '"' + str(self.labels[x]) + '"' for x in self.labels.keys())
labels = ",".join(
x + "=" + '"' + str(self.labels[x]) + '"' for x in self.labels.keys()
)
return f"{self.prefix}_{self.value_name}{{{labels}}} {self.value}"
class Collector(object):
def __init__(self):
#self.finalcommander_url = "radio.animebits.moe/api/fcmm_status"
# self.finalcommander_url = "radio.animebits.moe/api/fcmm_status"
self.fcmm_urls = ["https://radio.animebits.moe/api/fcmm_status"]
def _fetch_json(self, url):
try:
try:
r = requests.get(url)
data = json.loads(r.text)
return data
return data
except json.JSONDecodeError:
raise CollectorException(f"Failed to parse JSON at {url}")
except requests.exceptions.ConnectionError:
@ -36,11 +42,11 @@ class Collector(object):
def get_fcmm(self, url):
data = self._fetch_json(url)
if "public_key" not in data.keys() or "servers" not in data.keys():
raise CollectorException("FinalCommander JSON seems to be wrong.")
return data
return data
def get_instances(self, fcmm_data):
for server in fcmm_data["servers"]:
@ -64,7 +70,9 @@ class Collector(object):
up = 0
metrics.append(Metric("fcmm", "up", {"url": url}, up))
servers_data = [x for y in [self.get_instances(fcmm) for fcmm in fcmm_data] for x in y]
servers_data = [
x for y in [self.get_instances(fcmm) for fcmm in fcmm_data] for x in y
]
for server_data in servers_data:
baselabel = {"server": server_data["fcmm_data"]["Address"]}
@ -80,21 +88,34 @@ class Collector(object):
for name, data in server_data["statistics"].items():
if name == "http" or name == "tls":
for k,v in data.items():
for subtype,value in v.items():
metrics.append(Metric("orbt_stats", f"{name}_{k}", {**baselabel, **{k: subtype}}, value))
for k, v in data.items():
for subtype, value in v.items():
metrics.append(
Metric(
"orbt_stats",
f"{name}_{k}",
{**baselabel, **{k: subtype}},
value,
)
)
else:
for valuetype, value in data.items():
metrics.append(Metric("orbt_stats", name, {**baselabel, **{"type": valuetype}}, value))
metrics.append(
Metric(
"orbt_stats",
name,
{**baselabel, **{"type": valuetype}},
value,
)
)
for name, value in server_data["database"].items():
metrics.append(Metric("orbt_db", name, {**baselabel}, value))
return metrics
class CollectorException(Exception):
"""
Base exception class raised by Collector
"""
"""
Base exception class raised by Collector
"""

View File

@ -1,14 +1,15 @@
import socket
import signal
from ipaddress import ip_address
from http.server import HTTPServer,BaseHTTPRequestHandler
from http.server import HTTPServer, BaseHTTPRequestHandler
from selectors import DefaultSelector, EVENT_READ
from src import Collector
from src import Collector
class PromServer(HTTPServer):
class PromServer(HTTPServer):
def __init__(self, address):
if ip_address(address[0]).version == 6:
if ip_address(address[0]).version == 6:
self.address_family = socket.AF_INET6
super().__init__(address, self.RequestHandler)
@ -19,14 +20,14 @@ class PromServer(HTTPServer):
metrics = [x.format_prom() for x in self.server.collector.collect()]
output = '\n'.join(metrics) + '\n'
output = "\n".join(metrics) + "\n"
self.send_response(200)
self.end_headers()
self.wfile.write(output.encode())
def signal_handler(self, signum, frame):
print('Signal handler called with signal', signum)
self.interrupt_write.send(b'\0')
print("Signal handler called with signal", signum)
self.interrupt_write.send(b"\0")
def serve_forever(self):
sel = DefaultSelector()
@ -41,7 +42,7 @@ class PromServer(HTTPServer):
self.handle_request()
def start(self):
self.collector = Collector.Collector()
self.collector = Collector.Collector()
self.interrupt_read, self.interrupt_write = socket.socketpair()
signal.signal(signal.SIGINT, self.signal_handler)
self.serve_forever()

View File

@ -3,14 +3,31 @@ import argparse
from src import PrometheusServer
def start():
parser = argparse.ArgumentParser(description="Run radio exporter")
parser.add_argument("-p", "--port", metavar="port", action='store', type=int, default=8888, help='Port for http server to listen on')
parser.add_argument("-a", "--address", metavar="address", action='store', default='0.0.0.0', help='Address for http server to listen on')
parser.add_argument(
"-p",
"--port",
metavar="port",
action="store",
type=int,
default=8888,
help="Port for http server to listen on",
)
parser.add_argument(
"-a",
"--address",
metavar="address",
action="store",
default="0.0.0.0",
help="Address for http server to listen on",
)
args = parser.parse_args()
server = PrometheusServer.PromServer((args.address, args.port))
server = PrometheusServer.PromServer((args.address, args.port))
server.start()
if __name__ == '__main__':
if __name__ == "__main__":
start()