18 Commits
1.1.1 ... 1.3.0

Author SHA1 Message Date
Esteban Sánchez
940b5c6242 Merge pull request #20 from jsawatzky/master
Return metrics on connection error
2023-05-09 15:52:59 +02:00
Jacob Sawatzky
f47ebe94d0 Fix typo 2023-04-25 21:10:56 -04:00
Jacob Sawatzky
e1ed34147c Return matrics on connection error 2023-04-25 21:06:30 -04:00
Esteban Sánchez
bc8676ed30 Changed reference to use GHCR 2023-03-16 16:44:08 +01:00
Esteban Sanchez
fb12d50373 Merge pull request #14 from averyanalex/master
Update dependencies
2022-02-28 09:45:10 +01:00
Alex Averyanov
bb3695ece6 Update dependencies 2022-01-11 22:56:54 +03:00
Esteban Sánchez
a9a3e5d1e6 Push docker image to GHCR 2021-08-13 13:02:04 +02:00
Esteban Sánchez
6c885b5fa0 Version 1.2.0 2021-07-17 23:19:38 +02:00
Esteban Sanchez
039f7a7ef4 Merge pull request #9 from jhollowe/logging-and-signals
Fixed logging and exit errors
2021-07-17 23:18:00 +02:00
Esteban Sanchez
8bdaa48c48 Merge pull request #10 from jhollowe/file-configs
Allow files as config sources
2021-07-17 23:16:48 +02:00
Esteban Sanchez
e8dd24f731 Merge pull request #8 from jhollowe/master
Add multi-arch Docker build support
2021-07-17 23:15:00 +02:00
John Hollowell
12dcad10d5 Setup logging before config loading 2021-07-16 23:24:58 +00:00
John Hollowell
597307c230 Allow files as config source
Allow "FILE__"+config_name to point to a file containing the config value.
This format matches linuxserver.io containers and is comonly used in other containers as well.

e.g. FILE__QBITTORRENT_HOST contains "/run/secrets/q_host" and the contents of the "/run/secrets/q_host" is "1.2.3.4"
2021-07-16 23:24:58 +00:00
John Hollowell
a25005b6a0 Fixed logging and exit errors
* Create logger in module so it is always available (still configured in main())
* Allow signals sent multiple times to forcibly kill the exporter
2021-07-16 23:24:26 +00:00
John Hollowell
cfe62f8115 Remove hardcoded username in docker tags 2021-07-16 21:15:47 +00:00
John Hollowell
b5d20e3fe6 Add multiple architechture build support
Add auto builds for x86, x86_64, and arm64
2021-07-16 21:01:54 +00:00
Esteban Sánchez
0ff6a56f18 Version 1.1.2 2021-07-03 23:33:39 +02:00
Esteban Sánchez
2d968bc8e8 Added attrdict as requirement 2021-07-03 20:59:50 +02:00
4 changed files with 72 additions and 42 deletions

View File

@@ -13,6 +13,9 @@ jobs:
- name: 'Checkout GitHub Action'
uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
@@ -33,8 +36,27 @@ jobs:
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build and push docker
- name: Build and push docker to DockerHub
uses: docker/build-push-action@v2
with:
push: true
tags: esanchezm/prometheus-qbittorrent-exporter:latest,esanchezm/prometheus-qbittorrent-exporter:${{ steps.extract_branch.outputs.tag }}
platforms: linux/amd64,linux/arm64,linux/386
tags: |
${{ secrets.REGISTRY_USERNAME }}/prometheus-qbittorrent-exporter:latest
${{ secrets.REGISTRY_USERNAME }}/prometheus-qbittorrent-exporter:${{ steps.extract_branch.outputs.tag }}
- name: Login to Github Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.GHCR_PERSONAL_TOKEN }}
- name: Build and push docker to Github Container Registry
uses: docker/build-push-action@v2
with:
push: true
platforms: linux/amd64,linux/arm64,linux/386
tags: |
ghcr.io/${{ secrets.REGISTRY_USERNAME }}/prometheus-qbittorrent-exporter:latest
ghcr.io/${{ secrets.REGISTRY_USERNAME }}/prometheus-qbittorrent-exporter:${{ steps.extract_branch.outputs.tag }}

View File

@@ -20,7 +20,11 @@ qbittorrent-exporter
Another option is run it in a docker container.
```
docker run -e QBITTORRENT_PORT=8080 -e QBITTORRENT_HOST=myserver.local -p 8000:8000 esanchezm/prometheus-qbittorrent-exporter
docker run \
-e QBITTORRENT_PORT=8080 \
-e QBITTORRENT_HOST=myserver.local \
-p 8000:8000 \
ghcr.io/esanchezm/prometheus-qbittorrent-exporter
```
Add this to your prometheus.yml
```

View File

@@ -14,7 +14,7 @@ from pythonjsonlogger import jsonlogger
# Enable dumps on stderr in case of segfault
faulthandler.enable()
logger = None
logger = logging.getLogger()
class QbittorrentMetricsCollector():
@@ -29,7 +29,6 @@ class QbittorrentMetricsCollector():
def __init__(self, config):
self.config = config
self.torrents = None
self.client = Client(
host=config["host"],
port=config["port"],
@@ -38,12 +37,6 @@ class QbittorrentMetricsCollector():
)
def collect(self):
try:
self.torrents = self.client.torrents.info()
except Exception as e:
logger.error(f"Couldn't get server info: {e}")
return None
metrics = self.get_qbittorrent_metrics()
for metric in metrics:
@@ -75,11 +68,8 @@ class QbittorrentMetricsCollector():
try:
response = self.client.transfer.info
version = self.client.app.version
self.torrents = self.client.torrents.info()
except APIConnectionError as e:
logger.error(f"Couldn't get server info: {e.error_message}")
except Exception:
logger.error(f"Couldn't get server info")
except Exception as e:
logger.error(f"Couldn't get server info: {e}")
return [
{
@@ -120,17 +110,15 @@ class QbittorrentMetricsCollector():
def get_qbittorrent_torrent_tags_metrics(self):
try:
categories = self.client.torrent_categories.categories
torrents = self.client.torrents.info()
except Exception as e:
logger.error(f"Couldn't fetch categories: {e}")
return []
if not self.torrents:
logger.error(f"Couldn't fetch torrent info: {e}")
return []
metrics = []
categories.Uncategorized = AttrDict({'name': 'Uncategorized', 'savePath': ''})
for category in categories:
category_torrents = [t for t in self.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}"
@@ -152,50 +140,66 @@ class QbittorrentMetricsCollector():
class SignalHandler():
def __init__(self):
self.shutdown = False
self.shutdownCount = 0
# Register signal handler
signal.signal(signal.SIGINT, self._on_signal_received)
signal.signal(signal.SIGTERM, self._on_signal_received)
def is_shutting_down(self):
return self.shutdown
return self.shutdownCount > 0
def _on_signal_received(self, signal, frame):
if self.shutdownCount > 1:
logger.warn("Forcibly killing exporter")
sys.exit(1)
logger.info("Exporter is shutting down")
self.shutdown = True
self.shutdownCount += 1
def get_config_value(key, default=""):
input_path = os.environ.get("FILE__" + key, None)
if input_path is not None:
try:
with open(input_path, "r") as input_file:
return input_file.read().strip()
except IOError as e:
logger.error(f"Unable to read value for {key} from {input_path}: {str(e)}")
return os.environ.get(key, default)
def main():
config = {
"host": os.environ.get("QBITTORRENT_HOST", ""),
"port": os.environ.get("QBITTORRENT_PORT", ""),
"username": os.environ.get("QBITTORRENT_USER", ""),
"password": os.environ.get("QBITTORRENT_PASS", ""),
"exporter_port": int(os.environ.get("EXPORTER_PORT", "8000")),
"log_level": os.environ.get("EXPORTER_LOG_LEVEL", "INFO"),
"metrics_prefix": os.environ.get("METRICS_PREFIX", "qbittorrent"),
}
# Register signal handler
signal_handler = SignalHandler()
# Init logger
# Init logger so it can be used
logHandler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter(
"%(asctime) %(levelname) %(message)",
datefmt="%Y-%m-%d %H:%M:%S"
)
logHandler.setFormatter(formatter)
logger = logging.getLogger()
logger.addHandler(logHandler)
logger.setLevel("INFO") # default until config is loaded
config = {
"host": get_config_value("QBITTORRENT_HOST", ""),
"port": get_config_value("QBITTORRENT_PORT", ""),
"username": get_config_value("QBITTORRENT_USER", ""),
"password": get_config_value("QBITTORRENT_PASS", ""),
"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"),
}
# set level once config has been loaded
logger.setLevel(config["log_level"])
# Register signal handler
signal_handler = SignalHandler()
if not config["host"]:
logger.error("No host specified, please set QBITTORRENT_HOST environment variable")
sys.exit(1)
if not config["port"]:
logger.error("No post 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

View File

@@ -6,7 +6,7 @@ with open("README.md", "r") as fh:
setup(
name='prometheus-qbittorrent-exporter',
packages=['qbittorrent_exporter'],
version='1.1.1',
version='1.2.0',
long_description=long_description,
long_description_content_type="text/markdown",
description='Prometheus exporter for qbittorrent',
@@ -17,7 +17,7 @@ setup(
keywords=['prometheus', 'qbittorrent'],
classifiers=[],
python_requires='>=3',
install_requires=['qbittorrent-api==2021.3.18', 'prometheus_client==0.8.0', 'python-json-logger==0.1.5'],
install_requires=['attrdict==2.0.1', 'qbittorrent-api==2022.1.27', 'prometheus_client==0.12.0 ', 'python-json-logger==2.0.2'],
entry_points={
'console_scripts': [
'qbittorrent-exporter=qbittorrent_exporter.exporter:main',