fixes and typos
removed last trace of qbittorrent naming created readme
This commit is contained in:
parent
f9866ee2b7
commit
610ca5b6b4
5 changed files with 948 additions and 135 deletions
51
README.md
51
README.md
|
@ -1,6 +1,6 @@
|
||||||
# Prometheus qBittorrent exporter
|
# Prometheus Immich exporter
|
||||||
|
|
||||||
A prometheus exporter for qBitorrent. Get metrics from a server and offers them in a prometheus format.
|
A prometheus exporter for Immich. Get metrics from a server and offers them in a prometheus format.
|
||||||
|
|
||||||
|
|
||||||
## How to use it
|
## How to use it
|
||||||
|
@ -14,47 +14,54 @@ pip3 install prometheus-qbittorrent-exporter
|
||||||
Then you can run it with
|
Then you can run it with
|
||||||
|
|
||||||
```
|
```
|
||||||
qbittorrent-exporter
|
immich-exporter
|
||||||
```
|
```
|
||||||
|
|
||||||
Another option is run it in a docker container.
|
Another option is to run it in a docker container. Here is an example docker run command
|
||||||
|
|
||||||
```
|
```
|
||||||
docker run -e QBITTORRENT_PORT=8080 -e QBITTORRENT_HOST=myserver.local -p 8000:8000 esanchezm/prometheus-qbittorrent-exporter
|
docker run -e IMMICH_PORT=8010 -e IMMICH_HOST=192.168.178.1 -p 8000:8000 friendlyfriend/prometheus-immich-exporter
|
||||||
```
|
```
|
||||||
Add this to your prometheus.yml
|
Add this to your prometheus.yml
|
||||||
```
|
```
|
||||||
- job_name: "qbittorrent_exporter"
|
- job_name: "qbittorrent_exporter"
|
||||||
static_configs:
|
static_configs:
|
||||||
- targets: ['yourqbittorrentexporter:port']
|
- targets: ['yourimmichexporter:port']
|
||||||
```
|
```
|
||||||
The application reads configuration using environment variables:
|
The application reads configuration using environment variables:
|
||||||
|
|
||||||
| Environment variable | Default | Description |
|
| Environment variable | Default | Description |
|
||||||
| -------------------- | ------------- | ----------- |
|
|----------------------|----------|----------------------------------------------------|
|
||||||
| `QBITTORRENT_HOST` | | qbittorrent server hostname |
|
| `IMMICH_HOST` | | immich server hostname |
|
||||||
| `QBITTORRENT_PORT` | | qbittorrent server port |
|
| `IMMICH_PORT` | | immich server port |
|
||||||
| `QBITTORRENT_USER` | `""` | qbittorrent username |
|
|
||||||
| `QBITTORRENT_PASS` | `""` | qbittorrent password |
|
|
||||||
| `EXPORTER_PORT` | `8000` | Exporter listening port |
|
| `EXPORTER_PORT` | `8000` | Exporter listening port |
|
||||||
| `EXPORTER_LOG_LEVEL` | `INFO` | Log level. One of: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |
|
| `EXPORTER_LOG_LEVEL` | `INFO` | Log level. One of: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |
|
||||||
| `METRICS_PREFIX` | `qbittorrent` | Prefix to add to all the metrics |
|
| `METRICS_PREFIX` | `immich` | Prefix to add to all the metrics |
|
||||||
|
|
||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
|
|
||||||
These are the metrics this program exports, assuming the `METRICS_PREFIX` is `qbittorrent`:
|
These are the metrics this program exports, assuming the `METRICS_PREFIX` is `immich`:
|
||||||
|
|
||||||
|
|
||||||
| Metric name | Type | Description |
|
| `metric name` | `description` |
|
||||||
| --------------------------------------------------- | -------- | ---------------- |
|
|------------------------------------------|---------------------------------------------------------------------------|
|
||||||
| `qbittorrent_up` | gauge | Whether if the qBittorrent server is answering requests from this exporter. A `version` label with the server version is added |
|
| `immich_server_info_version_number` | `pings server and passes version number with the use of labels={version}` |
|
||||||
| `qbittorrent_connected` | gauge | Whether if the qBittorrent server is connected to the Bittorrent network. |
|
| `immich_server_info_diskAvailable` | `available space on disk` |
|
||||||
| `qbittorrent_firewalled` | gauge | Whether if the qBittorrent server is connected to the Bittorrent network but is behind a firewall. |
|
| `immich_server_info_totalDiskSize` | `total disk size` |
|
||||||
| `qbittorrent_dht_nodes` | gauge | Number of DHT nodes connected to |
|
| `immich_server_info_diskUse` | `disk space used by your system` |
|
||||||
| `qbittorrent_dl_info_data` | counter | Data downloaded since the server started, in bytes |
|
| `immich_server_info_diskUsagePercentage` | `same as above but in percentage` |
|
||||||
| `qbittorrent_up_info_data` | counter | Data uploaded since the server started, in bytes |
|
|
||||||
| `qbittorrent_torrents_count` | gauge | Number of torrents for each `category` and `status`. Example: `qbittorrent_torrents_count{category="movies",status="downloading"}`|
|
| `metric name` | `description` |
|
||||||
|
|---------------------------------------|---------------------------------------------|
|
||||||
|
| `immich_server_stats_user_count` | `number of users signed up ` |
|
||||||
|
| `immich_server_stats_photos_by_users` | `array of users and their amount of photos` |
|
||||||
|
| `immich_server_stats_photos_growth` | `sum of photos of all users` |
|
||||||
|
| `immich_server_stats_videos_by_users` | `array of users and their amount of videos` |
|
||||||
|
| `immich_server_stats_videos_growth` | `sum of all videos of all users` |
|
||||||
|
| `immich_server_stats_usage_by_users` | `the disk space each user uses` |
|
||||||
|
| `immich_server_stats_usage_growth` | `sum of disk space taken up by all users` |
|
||||||
|
|
||||||
|
|
||||||
## Screenshot
|
## Screenshot
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,20 @@
|
||||||
|
|
||||||
## Import
|
## Import
|
||||||
|
|
||||||
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.
|
To import the dashboard into your grafana, download the [dashboard.json](https://raw.githubusercontent.com/friendlyFriend/immich-qbittorrent-exporter/master/grafana/dashboard.json) file and import it into your server. Select your prometheus instance and that should be all.
|
||||||
|
|
||||||
|
The graphs can be customized in their relative time. Mind that it takes time to populate them if you set relative time to monthly or yearly
|
||||||
|
|
||||||
|
|
||||||
|
| Relative time | entry |
|
||||||
|
|--------------------------|----------|
|
||||||
|
| `the current day so far` | `now/d` |
|
||||||
|
| `the current week` | `now/w` |
|
||||||
|
| `current month` | `now/M` |
|
||||||
|
| `current year` | `now/y` |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Screenshot
|
## Screenshot
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Binary file not shown.
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 258 KiB |
|
@ -4,7 +4,6 @@ import sys
|
||||||
import signal
|
import signal
|
||||||
import faulthandler
|
import faulthandler
|
||||||
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
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
|
||||||
|
@ -16,7 +15,7 @@ faulthandler.enable()
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
class QbittorrentMetricsCollector():
|
class ImmichMetricsCollector:
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.config = config
|
self.config = config
|
||||||
|
@ -43,13 +42,14 @@ class QbittorrentMetricsCollector():
|
||||||
metrics = []
|
metrics = []
|
||||||
metrics.extend(self.get_immich_server_version_number())
|
metrics.extend(self.get_immich_server_version_number())
|
||||||
metrics.extend(self.get_immich_server_info())
|
metrics.extend(self.get_immich_server_info())
|
||||||
metrics.extend(self.get_immich_users_stat())
|
metrics.extend(self.get_immich_users_stat)
|
||||||
|
metrics.extend(self.get_immich_users_stat_growth())
|
||||||
|
|
||||||
return metrics
|
return metrics
|
||||||
|
|
||||||
def get_immich_users_stat(self):
|
def get_immich_users_stat_growth(self):
|
||||||
|
|
||||||
|
|
||||||
|
global response_user_stats
|
||||||
try:
|
try:
|
||||||
endpoint_user_stats = "/api/server-info/stats"
|
endpoint_user_stats = "/api/server-info/stats"
|
||||||
response_user_stats = requests.request(
|
response_user_stats = requests.request(
|
||||||
|
@ -61,25 +61,58 @@ class QbittorrentMetricsCollector():
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
logger.error(f"Couldn't get server version: {e}")
|
logger.error(f"Couldn't get server version: {e}")
|
||||||
|
|
||||||
metrics = []
|
userData = response_user_stats.json()["usageByUser"]
|
||||||
|
# photos growth gauge
|
||||||
userCount = len(response_user_stats.json()["usageByUser"])
|
userCount = len(response_user_stats.json()["usageByUser"])
|
||||||
|
photos_growth_total = 0
|
||||||
|
videos_growth_total = 0
|
||||||
|
usage_growth_total = 0
|
||||||
|
|
||||||
#userCount
|
for x in range(0, userCount):
|
||||||
metrics.append(
|
photos_growth_total += userData[x]["photos"]
|
||||||
|
# total video growth
|
||||||
|
videos_growth_total += userData[x]["videos"]
|
||||||
|
# total disk growth
|
||||||
|
usage_growth_total += userData[x]["usage"]
|
||||||
|
|
||||||
|
return [
|
||||||
{
|
{
|
||||||
"name": f"{self.config['metrics_prefix']}_user_count",
|
"name": f"{self.config['metrics_prefix']}_server_stats_user_count",
|
||||||
"value": userCount,
|
"value": userCount,
|
||||||
"help": "number of users on the immich server"
|
"help": "number of users on the immich server"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": f"{self.config['metrics_prefix']}_server_stats_photos_growth",
|
||||||
|
"value": photos_growth_total,
|
||||||
|
"help": "photos counter that is added or removed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": f"{self.config['metrics_prefix']}_server_stats_videos_growth",
|
||||||
|
"value": videos_growth_total,
|
||||||
|
"help": "videos counter that is added or removed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": f"{self.config['metrics_prefix']}_server_stats_usage_growth",
|
||||||
|
"value": usage_growth_total,
|
||||||
|
"help": "videos counter that is added or removed"
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
#Photos
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_immich_users_stat(self):
|
||||||
|
|
||||||
|
metrics = []
|
||||||
|
# To get the user count an api-endpoint exists but this works too. As a result one less api call is being made
|
||||||
|
userCount = len(response_user_stats.json()["usageByUser"])
|
||||||
|
# json array of all users with stats
|
||||||
userData = response_user_stats.json()["usageByUser"]
|
userData = response_user_stats.json()["usageByUser"]
|
||||||
|
|
||||||
for x in range(0, userCount):
|
for x in range(0, userCount):
|
||||||
metrics.append(
|
metrics.append(
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": f"{self.config['metrics_prefix']}_photos_by_user",
|
"name": f"{self.config['metrics_prefix']}_server_stats_photos_by_users",
|
||||||
"value": userData[x]['photos'],
|
"value": userData[x]['photos'],
|
||||||
"labels": {
|
"labels": {
|
||||||
"firstName": userData[x]["userFirstName"],
|
"firstName": userData[x]["userFirstName"],
|
||||||
|
@ -94,7 +127,7 @@ class QbittorrentMetricsCollector():
|
||||||
for x in range(0, userCount):
|
for x in range(0, userCount):
|
||||||
metrics.append(
|
metrics.append(
|
||||||
{
|
{
|
||||||
"name": f"{self.config['metrics_prefix']}_videos_by_user",
|
"name": f"{self.config['metrics_prefix']}_server_stats_videos_by_users",
|
||||||
"value": userData[x]['videos'],
|
"value": userData[x]['videos'],
|
||||||
"labels": {
|
"labels": {
|
||||||
"firstName": userData[x]["userFirstName"],
|
"firstName": userData[x]["userFirstName"],
|
||||||
|
@ -108,7 +141,7 @@ class QbittorrentMetricsCollector():
|
||||||
for x in range(0, userCount):
|
for x in range(0, userCount):
|
||||||
metrics.append(
|
metrics.append(
|
||||||
{
|
{
|
||||||
"name": f"{self.config['metrics_prefix']}_usage_by_user",
|
"name": f"{self.config['metrics_prefix']}_server_stats_usage_by_users",
|
||||||
"value": (userData[x]['usage']),
|
"value": (userData[x]['usage']),
|
||||||
"labels": {
|
"labels": {
|
||||||
"firstName": userData[x]["userFirstName"],
|
"firstName": userData[x]["userFirstName"],
|
||||||
|
@ -133,30 +166,26 @@ class QbittorrentMetricsCollector():
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
logger.error(f"Couldn't get server version: {e}")
|
logger.error(f"Couldn't get server version: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"name": f"{self.config['metrics_prefix']}_diskAvailable",
|
"name": f"{self.config['metrics_prefix']}_server_info_diskAvailable",
|
||||||
"value": (response_server_info.json()["diskAvailableRaw"]),
|
"value": (response_server_info.json()["diskAvailableRaw"]),
|
||||||
"help": "Available space on disk",
|
"help": "Available space on disk",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": f"{self.config['metrics_prefix']}_totalDiskSize",
|
"name": f"{self.config['metrics_prefix']}_server_info_totalDiskSize",
|
||||||
"value": (response_server_info.json()["diskSizeRaw"]),
|
"value": (response_server_info.json()["diskSizeRaw"]),
|
||||||
"help": "tota disk size",
|
"help": "tota disk size",
|
||||||
# "type": "counter"
|
# "type": "counter"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": f"{self.config['metrics_prefix']}_diskUse",
|
"name": f"{self.config['metrics_prefix']}_server_info_diskUse",
|
||||||
"value": (response_server_info.json()["diskUseRaw"]),
|
"value": (response_server_info.json()["diskUseRaw"]),
|
||||||
"help": "disk space in use",
|
"help": "disk space in use",
|
||||||
# "type": "counter"
|
# "type": "counter"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": f"{self.config['metrics_prefix']}_diskUsagePercentage",
|
"name": f"{self.config['metrics_prefix']}_server_info_diskUsagePercentage",
|
||||||
"value": (response_server_info.json()["diskUsagePercentage"]),
|
"value": (response_server_info.json()["diskUsagePercentage"]),
|
||||||
"help": "disk usage in percent",
|
"help": "disk usage in percent",
|
||||||
# "type": "counter"
|
# "type": "counter"
|
||||||
|
@ -166,6 +195,7 @@ class QbittorrentMetricsCollector():
|
||||||
def get_immich_server_version_number(self):
|
def get_immich_server_version_number(self):
|
||||||
|
|
||||||
server_version_endpoint = "/api/server-info/version"
|
server_version_endpoint = "/api/server-info/version"
|
||||||
|
response_server_version = ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
@ -182,10 +212,9 @@ class QbittorrentMetricsCollector():
|
||||||
str(response_server_version.json()["patch"])
|
str(response_server_version.json()["patch"])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"name": f"{self.config['metrics_prefix']}_version_number",
|
"name": f"{self.config['metrics_prefix']}_server_info_version_number",
|
||||||
"value": bool(server_version_number),
|
"value": bool(server_version_number),
|
||||||
"help": "server version number",
|
"help": "server version number",
|
||||||
"labels": {"version": server_version_number}
|
"labels": {"version": server_version_number}
|
||||||
|
@ -194,14 +223,14 @@ class QbittorrentMetricsCollector():
|
||||||
]
|
]
|
||||||
|
|
||||||
def combine_url(self, api_endpoint):
|
def combine_url(self, api_endpoint):
|
||||||
|
prefix_url = "http://"
|
||||||
base_url = self.config["immich_host"]
|
base_url = self.config["immich_host"]
|
||||||
base_url_port = self.config["immich_port"]
|
base_url_port = self.config["immich_port"]
|
||||||
combined_url = base_url + ":" + base_url_port + api_endpoint
|
combined_url = prefix_url + base_url + ":" + base_url_port + api_endpoint
|
||||||
|
|
||||||
return combined_url
|
return combined_url
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SignalHandler():
|
class SignalHandler():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.shutdownCount = 0
|
self.shutdownCount = 0
|
||||||
|
@ -261,13 +290,16 @@ def main():
|
||||||
if not config["immich_host"]:
|
if not config["immich_host"]:
|
||||||
logger.error("No host specified, please set IMMICH_HOST environment variable")
|
logger.error("No host specified, please set IMMICH_HOST environment variable")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
if not config["immich_port"]:
|
||||||
|
logger.error("No host specified, please set IMMICH_PORT environment variable")
|
||||||
|
sys.exit(1)
|
||||||
if not config["token"]:
|
if not config["token"]:
|
||||||
logger.error("No token specified, please set IMMICH_API_TOKEN environment variable")
|
logger.error("No token specified, please set IMMICH_API_TOKEN environment variable")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# 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(ImmichMetricsCollector(config))
|
||||||
|
|
||||||
# Start server
|
# Start server
|
||||||
start_http_server(config["exporter_port"])
|
start_http_server(config["exporter_port"])
|
||||||
|
|
Loading…
Reference in a new issue