mirror of
https://github.com/NohamR/prometheus-qbittorrent-exporter.git
synced 2025-05-24 00:59:28 +00:00
Remove unneeded attridict dependency, add comments
This commit is contained in:
parent
0ac406c476
commit
ea4bdecdcf
11
pdm.lock
generated
11
pdm.lock
generated
@ -6,16 +6,7 @@ groups = ["default"]
|
|||||||
cross_platform = true
|
cross_platform = true
|
||||||
static_urls = false
|
static_urls = false
|
||||||
lock_version = "4.3"
|
lock_version = "4.3"
|
||||||
content_hash = "sha256:637d322b802d007082b71cf7d27382f3b6b5618434faf6b346358abe81fc2f7f"
|
content_hash = "sha256:ec00e4f386c7e3cac870ab101184e565ee290c82a8b3d759fb7ad2762d0366ba"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "attridict"
|
|
||||||
version = "0.0.8"
|
|
||||||
summary = "A dict implementation with support for easy and clean access of its values through attributes"
|
|
||||||
files = [
|
|
||||||
{file = "attridict-0.0.8-py3-none-any.whl", hash = "sha256:8ee65af81f7762354e4514c443bbc04786a924c8e3e610c7883d2efbf323df6d"},
|
|
||||||
{file = "attridict-0.0.8.tar.gz", hash = "sha256:23a17671b9439d36e2bdb0a69c09f033abab0900a9df178e0f89aa1b2c42c5cd"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
|
@ -9,12 +9,11 @@ dependencies = [
|
|||||||
"prometheus-client>=0.17.1",
|
"prometheus-client>=0.17.1",
|
||||||
"python-json-logger>=2.0.7",
|
"python-json-logger>=2.0.7",
|
||||||
"qbittorrent-api>=2023.9.53",
|
"qbittorrent-api>=2023.9.53",
|
||||||
"attridict>=0.0.8",
|
|
||||||
]
|
]
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["prometheus", "qbittorrent"]
|
keywords = ["prometheus", "qbittorrent"]
|
||||||
license = "GPL-3.0"
|
license = {text = "GPL-3.0"}
|
||||||
classifiers = []
|
classifiers = []
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
@ -3,7 +3,6 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import signal
|
import signal
|
||||||
import faulthandler
|
import faulthandler
|
||||||
import attridict
|
|
||||||
from qbittorrentapi import Client, TorrentStates
|
from qbittorrentapi import Client, TorrentStates
|
||||||
from prometheus_client import start_http_server
|
from prometheus_client import start_http_server
|
||||||
from prometheus_client.core import GaugeMetricFamily, CounterMetricFamily, REGISTRY
|
from prometheus_client.core import GaugeMetricFamily, CounterMetricFamily, REGISTRY
|
||||||
@ -18,7 +17,11 @@ faulthandler.enable()
|
|||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class TorrentStatus(StrEnum):
|
class TorrentStatuses(StrEnum):
|
||||||
|
"""
|
||||||
|
Represents possible torrent states.
|
||||||
|
"""
|
||||||
|
|
||||||
CHECKING = auto()
|
CHECKING = auto()
|
||||||
COMPLETE = auto()
|
COMPLETE = auto()
|
||||||
ERRORED = auto()
|
ERRORED = auto()
|
||||||
@ -27,21 +30,29 @@ class TorrentStatus(StrEnum):
|
|||||||
|
|
||||||
|
|
||||||
class MetricType(StrEnum):
|
class MetricType(StrEnum):
|
||||||
|
"""
|
||||||
|
Represents possible metric types (used in this project).
|
||||||
|
"""
|
||||||
|
|
||||||
GAUGE = auto()
|
GAUGE = auto()
|
||||||
COUNTER = auto()
|
COUNTER = auto()
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Metric:
|
class Metric:
|
||||||
|
"""
|
||||||
|
Contains data and metadata about a single counter or gauge.
|
||||||
|
"""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
value: int | float | bool
|
value: Any
|
||||||
labels: dict[str, str] = field(default_factory={})
|
labels: dict[str, str] = field(default_factory=lambda: {}) # Default to empty dict
|
||||||
help_text: str = ""
|
help_text: str = ""
|
||||||
metric_type: MetricType = MetricType.GAUGE
|
metric_type: MetricType = MetricType.GAUGE
|
||||||
|
|
||||||
|
|
||||||
class QbittorrentMetricsCollector:
|
class QbittorrentMetricsCollector:
|
||||||
def __init__(self, config: dict[str, str | int | bool]) -> None:
|
def __init__(self, config: dict) -> None:
|
||||||
self.config = config
|
self.config = config
|
||||||
self.client = Client(
|
self.client = Client(
|
||||||
host=config["host"],
|
host=config["host"],
|
||||||
@ -52,28 +63,40 @@ class QbittorrentMetricsCollector:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def collect(self) -> Iterable[GaugeMetricFamily | CounterMetricFamily]:
|
def collect(self) -> Iterable[GaugeMetricFamily | CounterMetricFamily]:
|
||||||
|
"""
|
||||||
|
Gets Metric objects representing the current state of qbittorrent and yields
|
||||||
|
Prometheus gauges.
|
||||||
|
"""
|
||||||
metrics: list[Metric] = self.get_qbittorrent_metrics()
|
metrics: list[Metric] = self.get_qbittorrent_metrics()
|
||||||
|
|
||||||
for metric in metrics:
|
for metric in metrics:
|
||||||
if metric.metric_type == MetricType.COUNTER:
|
if metric.metric_type == MetricType.COUNTER:
|
||||||
prom_metric = CounterMetricFamily(
|
prom_metric = CounterMetricFamily(
|
||||||
metric.name, metric.help_text, labels=metric.labels.keys()
|
metric.name, metric.help_text, labels=list(metric.labels.keys())
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
prom_metric = GaugeMetricFamily(
|
prom_metric = GaugeMetricFamily(
|
||||||
metric.name, metric.help_text, labels=metric.labels.keys()
|
metric.name, metric.help_text, labels=list(metric.labels.keys())
|
||||||
|
)
|
||||||
|
prom_metric.add_metric(
|
||||||
|
value=metric.value, labels=list(metric.labels.values())
|
||||||
)
|
)
|
||||||
prom_metric.add_metric(value=metric.value, labels=metric.labels.values())
|
|
||||||
yield prom_metric
|
yield prom_metric
|
||||||
|
|
||||||
def get_qbittorrent_metrics(self) -> list[Metric]:
|
def get_qbittorrent_metrics(self) -> list[Metric]:
|
||||||
|
"""
|
||||||
|
Calls and combines qbittorrent state metrics with torrent metrics.
|
||||||
|
"""
|
||||||
metrics: list[Metric] = []
|
metrics: list[Metric] = []
|
||||||
metrics.extend(self._get_qbittorrent_status_metrics())
|
metrics.extend(self._get_qbittorrent_status_metrics())
|
||||||
metrics.extend(self._get_qbittorrent_torrent_tags_metrics())
|
metrics.extend(self._get_qbittorrent_torrent_tags_metrics())
|
||||||
|
|
||||||
return metrics
|
return metrics
|
||||||
|
|
||||||
def _get_qbittorrent_status_metrics(self) -> list[dict]:
|
def _get_qbittorrent_status_metrics(self) -> list[Metric]:
|
||||||
|
"""
|
||||||
|
Returns metrics about the state of the qbittorrent server.
|
||||||
|
"""
|
||||||
response: dict[str, Any] = {}
|
response: dict[str, Any] = {}
|
||||||
version: str = ""
|
version: str = ""
|
||||||
|
|
||||||
@ -147,22 +170,24 @@ class QbittorrentMetricsCollector:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
metrics: list[Metric] = []
|
metrics: list[Metric] = []
|
||||||
categories.Uncategorized = attridict({"name": "Uncategorized", "savePath": ""})
|
|
||||||
|
# Match torrents to categories
|
||||||
for category in categories:
|
for category in categories:
|
||||||
category_torrents = [
|
category_torrents: list = [
|
||||||
t
|
torrent
|
||||||
for t in torrents
|
for torrent in torrents
|
||||||
if t["category"] == category
|
if torrent["category"] == category
|
||||||
or (category == "Uncategorized" and t["category"] == "")
|
or (category == "Uncategorized" and torrent["category"] == "")
|
||||||
]
|
]
|
||||||
|
|
||||||
for status in TorrentStatus:
|
# Match qbittorrentapi torrent state to local TorrenStatuses
|
||||||
status_prop = f"is_{status.value}"
|
for status in TorrentStatuses:
|
||||||
|
proposed_status: str = f"is_{status.value}"
|
||||||
status_torrents = [
|
status_torrents = [
|
||||||
t
|
torrent
|
||||||
for t in category_torrents
|
for torrent in category_torrents
|
||||||
if getattr(TorrentStates, status_prop).fget(
|
if getattr(TorrentStates, proposed_status).fget(
|
||||||
TorrentStates(t["state"])
|
TorrentStates(torrent["state"])
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
metrics.append(
|
metrics.append(
|
||||||
@ -255,7 +280,7 @@ def main():
|
|||||||
|
|
||||||
# Register our custom collector
|
# Register our custom collector
|
||||||
logger.info("Exporter is starting up")
|
logger.info("Exporter is starting up")
|
||||||
REGISTRY.register(QbittorrentMetricsCollector(config))
|
REGISTRY.register(QbittorrentMetricsCollector(config)) # type: ignore
|
||||||
|
|
||||||
# Start server
|
# Start server
|
||||||
start_http_server(config["exporter_port"])
|
start_http_server(config["exporter_port"])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user