1 Commits

Author SHA1 Message Date
Esteban Sánchez
c873cda618 Added more unittests 2023-11-20 16:17:28 +01:00
15 changed files with 226 additions and 1587 deletions

View File

@@ -11,63 +11,52 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Checkout GitHub Action'
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v1
- name: Docker hub meta
id: meta
uses: docker/metadata-action@v5
with:
flavor: |
latest=true
tags: |
type=semver,pattern=v{{version}}
type=ref,event=branch
type=sha
images: ${{ github.actor }}/prometheus-qbittorrent-exporter
- name: Extract branch name
shell: bash
run: |
tag=${GITHUB_REF#refs/tags/}
tag=${tag#refs/heads/}
if echo $tag | grep -q -E "[0-9]+\.[0-9]+\.[0-9]+"; then
tag="v$tag"
fi
echo "##[set-output name=tag;]$tag"
id: extract_branch
- name: Login to DockerHub
uses: docker/login-action@v3
uses: docker/login-action@v1
with:
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build and push docker to DockerHub
uses: docker/build-push-action@v5
uses: docker/build-push-action@v2
with:
push: true
platforms: linux/amd64,linux/arm64,linux/386
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: GHCR Docker meta
id: metaghcr
uses: docker/metadata-action@v5
with:
flavor: |
latest=true
tags: |
type=semver,pattern=v{{version}}
type=ref,event=branch
type=sha
images: ghcr.io/${{ github.actor }}/prometheus-qbittorrent-exporter
${{ 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@v3
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.GHCR_PERSONAL_TOKEN }}
- name: Build and push docker to Github Container Registry
uses: docker/build-push-action@v5
uses: docker/build-push-action@v2
with:
push: true
platforms: linux/amd64,linux/arm64,linux/386
tags: ${{ steps.metaghcr.outputs.tags }}
labels: ${{ steps.metaghcr.outputs.labels }}
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

@@ -15,7 +15,7 @@ jobs:
checks: write
strategy:
matrix:
python-version: ["3.12"]
python-version: ["3.11"]
steps:
- uses: actions/checkout@v3

View File

@@ -12,7 +12,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: '3.12'
python-version: '3.6'
- name: Install dependencies
run: |
python -m pip install --upgrade pip

1
.gitignore vendored
View File

@@ -136,4 +136,3 @@ config.env
# Ignore ruff files
.ruff_cache
.DS_Store

View File

@@ -1,4 +1,4 @@
FROM python:3.12-alpine
FROM python:3.11-alpine
# Install package
WORKDIR /code

View File

@@ -6,7 +6,7 @@
A prometheus exporter for qBitorrent. Get metrics from a server and offers them in a prometheus format.
![](https://img.shields.io/github/license/esanchezm/prometheus-qbittorrent-exporter?style=for-the-badge) ![](https://img.shields.io/maintenance/yes/2023?style=for-the-badge) ![](https://img.shields.io/docker/pulls/esanchezm/prometheus-qbittorrent-exporter?style=for-the-badge) ![](https://img.shields.io/github/forks/esanchezm/prometheus-qbittorrent-exporter?style=for-the-badge) ![](https://img.shields.io/github/stars/esanchezm/prometheus-qbittorrent-exporter?style=for-the-badge) ![](https://img.shields.io/python/required-version-toml?tomlFilePath=https://raw.githubusercontent.com/esanchezm/prometheus-qbittorrent-exporter/master/pyproject.toml&style=for-the-badge) [![Coverage badge](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/esanchezm/prometheus-qbittorrent-exporter/python-coverage-comment-action-data/endpoint.json&label=tests%20coverage&style=for-the-badge)](https://htmlpreview.github.io/?https://github.com/esanchezm/prometheus-qbittorrent-exporter/blob/python-coverage-comment-action-data/htmlcov/index.html)
![](https://img.shields.io/maintenance/yes/2023?style=for-the-badge) ![](https://img.shields.io/docker/pulls/esanchezm/prometheus-qbittorrent-exporter?style=for-the-badge) ![](https://img.shields.io/github/forks/esanchezm/prometheus-qbittorrent-exporter?style=for-the-badge) ![](https://img.shields.io/github/stars/esanchezm/prometheus-qbittorrent-exporter?style=for-the-badge) ![](https://img.shields.io/python/required-version-toml?tomlFilePath=https://raw.githubusercontent.com/esanchezm/prometheus-qbittorrent-exporter/master/pyproject.toml&style=for-the-badge) [![Coverage badge](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/esanchezm/prometheus-qbittorrent-exporter/python-coverage-comment-action-data/endpoint.json&label=tests%20coverage&style=for-the-badge)](https://htmlpreview.github.io/?https://github.com/esanchezm/prometheus-qbittorrent-exporter/blob/python-coverage-comment-action-data/htmlcov/index.html)
## How to use it

View File

@@ -1,39 +0,0 @@
name: prom-qb-alltime
services:
esanchezm:
cpu_shares: 90
command: []
deploy:
resources:
limits:
memory: 7943M
environment:
- QBITTORRENT_HOST=192.168.1.58
- QBITTORRENT_PASS=Cp3mMdP!#
- QBITTORRENT_PORT=8188
- QBITTORRENT_USER=noham
image: prom-qb-alltime
labels:
icon: https://raw.githubusercontent.com/esanchezm/prometheus-qbittorrent-exporter/master/logo.png
ports:
- target: 8000
published: "9101"
protocol: tcp
restart: unless-stopped
volumes: []
devices: []
cap_add: []
network_mode: bridge
privileged: false
container_name: ""
x-casaos:
author: self
category: self
hostname: ""
icon: https://raw.githubusercontent.com/esanchezm/prometheus-qbittorrent-exporter/master/logo.png
index: /metrics
port_map: "9101"
scheme: http
store_app_id: relaxed_albert
title:
custom: prom-qb-alltime

View File

@@ -2,10 +2,8 @@
## Import
To import the dashboard into your grafana, download the [dashboard.json](https://raw.githubusercontent.com/nohamr/prometheus-qbittorrent-exporter/master/grafana/dashboard.json) file and import it into your server. Select your prometheus instance and that should be all.
To import the dashboard into your grafana, download the [dashboard.json](https://raw.githubusercontent.com/esanchezm/prometheus-qbittorrent-exporter/master/grafana/dashboard.json) file and import it into your server. Select your prometheus instance and that should be all.
## Screenshot
![](./screenshot1.png)
![](./screenshot2.png)
![](./screenshot3.png)
![](./screenshot.png)

File diff suppressed because it is too large Load Diff

BIN
grafana/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 701 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 420 KiB

View File

@@ -1,13 +1,11 @@
import faulthandler
import logging
import os
# from dotenv import load_dotenv
# load_dotenv()
import signal
import sys
import time
from dataclasses import dataclass, field
from enum import Enum, auto
from enum import StrEnum, auto
from typing import Any, Iterable
from prometheus_client import start_http_server
@@ -19,7 +17,8 @@ from qbittorrentapi import Client, TorrentStates
faulthandler.enable()
logger = logging.getLogger()
class MetricType(Enum):
class MetricType(StrEnum):
"""
Represents possible metric types (used in this project).
"""
@@ -86,22 +85,20 @@ class QbittorrentMetricsCollector:
"""
Returns metrics about the state of the qbittorrent server.
"""
maindata: dict[str, Any] = {}
response: dict[str, Any] = {}
version: str = ""
# Fetch data from API
try:
maindata = self.client.sync_maindata()
response = self.client.transfer.info
version = self.client.app.version
except Exception as e:
logger.error(f"Couldn't get server info: {e}")
server_state = maindata.get('server_state', {})
return [
Metric(
name=f"{self.config['metrics_prefix']}_up",
value=bool(server_state),
value=bool(response),
labels={"version": version},
help_text=(
"Whether the qBittorrent server is answering requests from this"
@@ -110,7 +107,7 @@ class QbittorrentMetricsCollector:
),
Metric(
name=f"{self.config['metrics_prefix']}_connected",
value=server_state.get("connection_status", "") == "connected",
value=response.get("connection_status", "") == "connected",
labels={}, # no labels in the example
help_text=(
"Whether the qBittorrent server is connected to the Bittorrent"
@@ -119,7 +116,7 @@ class QbittorrentMetricsCollector:
),
Metric(
name=f"{self.config['metrics_prefix']}_firewalled",
value=server_state.get("connection_status", "") == "firewalled",
value=response.get("connection_status", "") == "firewalled",
labels={}, # no labels in the example
help_text=(
"Whether the qBittorrent server is connected to the Bittorrent"
@@ -128,91 +125,24 @@ class QbittorrentMetricsCollector:
),
Metric(
name=f"{self.config['metrics_prefix']}_dht_nodes",
value=server_state.get("dht_nodes", 0),
value=response.get("dht_nodes", 0),
labels={}, # no labels in the example
help_text="Number of DHT nodes connected to.",
),
Metric(
name=f"{self.config['metrics_prefix']}_dl_info_data",
value=server_state.get("dl_info_data", 0),
value=response.get("dl_info_data", 0),
labels={}, # no labels in the example
help_text="Data downloaded since the server started, in bytes.",
metric_type=MetricType.COUNTER,
),
Metric(
name=f"{self.config['metrics_prefix']}_up_info_data",
value=server_state.get("up_info_data", 0),
value=response.get("up_info_data", 0),
labels={}, # no labels in the example
help_text="Data uploaded since the server started, in bytes.",
metric_type=MetricType.COUNTER,
),
Metric(
name=f"{self.config['metrics_prefix']}_alltime_dl",
value=server_state.get("alltime_dl", 0),
labels={}, # no labels in the example
help_text="Total data downloaded, in bytes.",
metric_type=MetricType.COUNTER,
),
Metric(
name=f"{self.config['metrics_prefix']}_alltime_ul",
value=server_state.get("alltime_ul", 0),
labels={}, # no labels in the example
help_text="Total data uploaded, in bytes.",
metric_type=MetricType.COUNTER,
),
Metric(
name=f"{self.config['metrics_prefix']}_total_peer_connections",
value=server_state.get("total_peer_connections", 0),
labels={}, # no labels in the example
help_text="total_peer_connections.",
metric_type=MetricType.COUNTER,
),
#### Disk metrics
Metric(
name=f"{self.config['metrics_prefix']}_write_cache_overload",
value=server_state.get("write_cache_overload", 0),
labels={}, # no labels in the example
help_text="write_cache_overload.",
metric_type=MetricType.COUNTER,
),
Metric(
name=f"{self.config['metrics_prefix']}_read_cache_overload",
value=server_state.get("read_cache_overload", 0),
labels={}, # no labels in the example
help_text="read_cache_overload.",
metric_type=MetricType.COUNTER,
),
Metric(
name=f"{self.config['metrics_prefix']}_read_cache_hits",
value=server_state.get("read_cache_hits", 0),
labels={}, # no labels in the example
help_text="read_cache_hits.",
metric_type=MetricType.COUNTER,
),
Metric(
name=f"{self.config['metrics_prefix']}_average_time_queue",
value=server_state.get("average_time_queue", 0),
labels={}, # no labels in the example
help_text="average_time_queue.",
metric_type=MetricType.COUNTER,
),
Metric(
name=f"{self.config['metrics_prefix']}_free_space_on_disk",
value=server_state.get("free_space_on_disk", 0),
labels={}, # no labels in the example
help_text="free_space_on_disk.",
metric_type=MetricType.COUNTER,
),
Metric(
name=f"{self.config['metrics_prefix']}_queued_io_jobs",
value=server_state.get("queued_io_jobs", 0),
labels={}, # no labels in the example
help_text="queued_io_jobs.",
metric_type=MetricType.COUNTER,
),
]
def _fetch_categories(self) -> dict:

View File

@@ -270,20 +270,6 @@ class TestQbittorrentMetricsCollector(unittest.TestCase):
help_text="Data uploaded since the server started, in bytes.",
metric_type=MetricType.COUNTER,
),
Metric(
name="qbittorrent_alltime_dl",
value=0,
labels={}, # no labels in the example
help_text="Total data downloaded, in bytes.",
metric_type=MetricType.COUNTER,
),
Metric(
name="qbittorrent_alltime_ul",
value=0,
labels={}, # no labels in the example
help_text="Total data uploaded, in bytes.",
metric_type=MetricType.COUNTER,
),
]
metrics = self.collector._get_qbittorrent_status_metrics()