diff --git a/arkose_prometheus/__init__.py b/arkose_prometheus/__init__.py new file mode 100644 index 0000000..6ec4e21 --- /dev/null +++ b/arkose_prometheus/__init__.py @@ -0,0 +1,34 @@ +import logging +import argparse +import asyncio +from prometheus_client import start_http_server +from . import arkose_gauge + +logger = logging.getLogger(__name__) + + +def main(): + parser = argparse.ArgumentParser("arkose_prometheus") + parser.add_argument("-p", "--port", type=int, default=9154) + parser.add_argument( + "-i", + "--scrape-interval", + type=int, + default=180, + help="Scrape interval, in seconds.", + ) + + args = parser.parse_args() + logging.basicConfig(level=logging.INFO) + + start_http_server(args.port) + logger.info("Listening on port %d...", args.port) + + try: + asyncio.run(arkose_gauge.scrape_metric_forever(interval=args.scrape_interval)) + except KeyboardInterrupt: + logger.info("Closing server (keyboard interrupt)") + + +if __name__ == "__main__": + main() diff --git a/arkose_prometheus/arkose_gauge.py b/arkose_prometheus/arkose_gauge.py new file mode 100644 index 0000000..c1b1bd9 --- /dev/null +++ b/arkose_prometheus/arkose_gauge.py @@ -0,0 +1,59 @@ +import asyncio +import aiohttp +import datetime +import re +import logging +from prometheus_client import Gauge + +logger = logging.getLogger(__name__) + +ARKOSES = { + "genevois": "https://genevois.arkose.com/", + "massy": "https://massy.arkose.com/", + "montreuil": "https://montreuil.arkose.com/", + "nation": "https://nation.arkose.com/", +} + +BLOCKPARK_OCCUPATION = Gauge( + "blockpark_occupation", "Blockpark occupation", ["blockpark"] +) + +GAUGE_RE = re.compile(r'
') + + +class FailedScrape(Exception): + pass + + +async def _scrape_arkose(arkose, session): + async with session.get(ARKOSES[arkose]) as resp: + if resp.status != 200: + raise FailedScrape("Non-200 error") + content = await resp.text() + + with open("/tmp/arkose_{}.html".format(arkose), "w") as handle: + handle.write(content) + + match = GAUGE_RE.search(content) + if not match: + raise FailedScrape("Could not extract gauge") + return int(match[1]) + + +async def scrape_metric_forever(interval: int): + async with aiohttp.ClientSession() as session: + while True: + start_time = datetime.datetime.now() + occupation_data = await asyncio.gather( + *[_scrape_arkose(arkose, session) for arkose in ARKOSES], + return_exceptions=True + ) + + for arkose, occup in zip(ARKOSES, occupation_data): + if isinstance(occup, Exception): + logger.warning("%s failed: %s", arkose, occup) + continue + BLOCKPARK_OCCUPATION.labels(blockpark=arkose).set(occup) + + delta_time = datetime.datetime.now() - start_time + await asyncio.sleep(interval - delta_time.total_seconds())