diff --git a/pdm.lock b/pdm.lock index 77b8935..a2be35f 100644 --- a/pdm.lock +++ b/pdm.lock @@ -6,18 +6,15 @@ groups = ["default"] cross_platform = true static_urls = false lock_version = "4.3" -content_hash = "sha256:619785556320f35b6aca0bf164725dc3afa5a1a978782d66a3add0b9e1ad8738" +content_hash = "sha256:637d322b802d007082b71cf7d27382f3b6b5618434faf6b346358abe81fc2f7f" [[package]] -name = "attrdict" -version = "2.0.1" -summary = "A dict with attribute-style access" -dependencies = [ - "six", -] +name = "attridict" +version = "0.0.8" +summary = "A dict implementation with support for easy and clean access of its values through attributes" files = [ - {file = "attrdict-2.0.1-py2.py3-none-any.whl", hash = "sha256:9432e3498c74ff7e1b20b3d93b45d766b71cbffa90923496f82c4ae38b92be34"}, - {file = "attrdict-2.0.1.tar.gz", hash = "sha256:35c90698b55c683946091177177a9e9c0713a0860f0e049febd72649ccd77b70"}, + {file = "attridict-0.0.8-py3-none-any.whl", hash = "sha256:8ee65af81f7762354e4514c443bbc04786a924c8e3e610c7883d2efbf323df6d"}, + {file = "attridict-0.0.8.tar.gz", hash = "sha256:23a17671b9439d36e2bdb0a69c09f033abab0900a9df178e0f89aa1b2c42c5cd"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 2278db1..0c3e925 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,10 +6,10 @@ authors = [ {name = "Esteban Sanchez", email = "esteban.sanchez@gmail.com"}, ] dependencies = [ - "attrdict>=2.0.1", "prometheus-client>=0.17.1", "python-json-logger>=2.0.7", "qbittorrent-api>=2023.9.53", + "attridict>=0.0.8", ] requires-python = ">=3.11" readme = "README.md" diff --git a/qbittorrent_exporter/exporter.py b/qbittorrent_exporter/exporter.py index 5e69547..a9b6111 100644 --- a/qbittorrent_exporter/exporter.py +++ b/qbittorrent_exporter/exporter.py @@ -3,9 +3,8 @@ import os import sys import signal import faulthandler -from attrdict import AttrDict +import attridict from qbittorrentapi import Client, TorrentStates -from qbittorrentapi.exceptions import APIConnectionError from prometheus_client import start_http_server from prometheus_client.core import GaugeMetricFamily, CounterMetricFamily, REGISTRY import logging @@ -17,7 +16,7 @@ faulthandler.enable() logger = logging.getLogger() -class QbittorrentMetricsCollector(): +class QbittorrentMetricsCollector: TORRENT_STATUSES = [ "checking", "complete", @@ -34,7 +33,7 @@ class QbittorrentMetricsCollector(): port=config["port"], username=config["username"], password=config["password"], - VERIFY_WEBUI_CERTIFICATE=config["verify_webui_certificate"] + VERIFY_WEBUI_CERTIFICATE=config["verify_webui_certificate"], ) def collect(self): @@ -98,13 +97,13 @@ class QbittorrentMetricsCollector(): "name": f"{self.config['metrics_prefix']}_dl_info_data", "value": response.get("dl_info_data", 0), "help": "Data downloaded this session (bytes)", - "type": "counter" + "type": "counter", }, { "name": f"{self.config['metrics_prefix']}_up_info_data", "value": response.get("up_info_data", 0), "help": "Data uploaded this session (bytes)", - "type": "counter" + "type": "counter", }, ] @@ -117,29 +116,43 @@ class QbittorrentMetricsCollector(): return [] metrics = [] - categories.Uncategorized = AttrDict({'name': 'Uncategorized', 'savePath': ''}) + categories.Uncategorized = attridict({"name": "Uncategorized", "savePath": ""}) for category in categories: - category_torrents = [t for t in torrents if t['category'] == category or (category == "Uncategorized" and t['category'] == "")] + category_torrents = [ + t + for t in torrents + if t["category"] == category + or (category == "Uncategorized" and t["category"] == "") + ] for status in self.TORRENT_STATUSES: status_prop = f"is_{status}" status_torrents = [ - t for t in category_torrents if getattr(TorrentStates, status_prop).fget(TorrentStates(t['state'])) + t + for t in category_torrents + if getattr(TorrentStates, status_prop).fget( + TorrentStates(t["state"]) + ) ] - metrics.append({ - "name": f"{self.config['metrics_prefix']}_torrents_count", - "value": len(status_torrents), - "labels": { - "status": status, - "category": category, - }, - "help": f"Number of torrents in status {status} under category {category}" - }) + metrics.append( + { + "name": f"{self.config['metrics_prefix']}_torrents_count", + "value": len(status_torrents), + "labels": { + "status": status, + "category": category, + }, + "help": ( + f"Number of torrents in status {status} under category" + f" {category}" + ), + } + ) return metrics -class SignalHandler(): +class SignalHandler: def __init__(self): self.shutdownCount = 0 @@ -157,6 +170,7 @@ class SignalHandler(): logger.info("Exporter is shutting down") self.shutdownCount += 1 + def get_config_value(key, default=""): input_path = os.environ.get("FILE__" + key, None) if input_path is not None: @@ -173,12 +187,11 @@ def main(): # Init logger so it can be used logHandler = logging.StreamHandler() formatter = jsonlogger.JsonFormatter( - "%(asctime) %(levelname) %(message)", - datefmt="%Y-%m-%d %H:%M:%S" + "%(asctime) %(levelname) %(message)", datefmt="%Y-%m-%d %H:%M:%S" ) logHandler.setFormatter(formatter) logger.addHandler(logHandler) - logger.setLevel("INFO") # default until config is loaded + logger.setLevel("INFO") # default until config is loaded config = { "host": get_config_value("QBITTORRENT_HOST", ""), @@ -188,7 +201,9 @@ def main(): "exporter_port": int(get_config_value("EXPORTER_PORT", "8000")), "log_level": get_config_value("EXPORTER_LOG_LEVEL", "INFO"), "metrics_prefix": get_config_value("METRICS_PREFIX", "qbittorrent"), - "verify_webui_certificate": get_config_value("VERIFY_WEBUI_CERTIFICATE", "True") == "True", + "verify_webui_certificate": ( + get_config_value("VERIFY_WEBUI_CERTIFICATE", "True") == "True" + ), } # set level once config has been loaded logger.setLevel(config["log_level"]) @@ -197,10 +212,14 @@ def main(): signal_handler = SignalHandler() if not config["host"]: - logger.error("No host specified, please set QBITTORRENT_HOST environment variable") + logger.error( + "No host specified, please set QBITTORRENT_HOST environment variable" + ) sys.exit(1) if not config["port"]: - logger.error("No port specified, please set QBITTORRENT_PORT environment variable") + logger.error( + "No port specified, please set QBITTORRENT_PORT environment variable" + ) sys.exit(1) # Register our custom collector @@ -209,9 +228,7 @@ def main(): # Start server start_http_server(config["exporter_port"]) - logger.info( - f"Exporter listening on port {config['exporter_port']}" - ) + logger.info(f"Exporter listening on port {config['exporter_port']}") while not signal_handler.is_shutting_down(): time.sleep(1)