Compare commits
10 commits
fb668bf3e2
...
c23ad910df
Author | SHA1 | Date | |
---|---|---|---|
|
c23ad910df | ||
|
f6d95209c0 | ||
|
3c6d7ef8ae | ||
|
edc8701419 | ||
|
23e2a7b939 | ||
|
e07e9fb459 | ||
|
7601be0f1b | ||
|
5a07ffdf0d | ||
|
99c9b84f40 | ||
|
513856beff |
13 changed files with 378 additions and 86 deletions
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
14
.idea/deployment.xml
Normal file
14
.idea/deployment.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false">
|
||||||
|
<serverData>
|
||||||
|
<paths name="//TOWER">
|
||||||
|
<serverdata>
|
||||||
|
<mappings>
|
||||||
|
<mapping local="$PROJECT_DIR$" web="/" />
|
||||||
|
</mappings>
|
||||||
|
</serverdata>
|
||||||
|
</paths>
|
||||||
|
</serverData>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
4
.idea/misc.xml
Normal file
4
.idea/misc.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (2)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/prometheus-immich-exporter.iml" filepath="$PROJECT_DIR$/.idea/prometheus-immich-exporter.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
8
.idea/prometheus-immich-exporter.iml
Normal file
8
.idea/prometheus-immich-exporter.iml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.10 (2)" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -14,7 +14,7 @@ RUN pip3 install .
|
||||||
|
|
||||||
ENV IMMICH_API_TOKEN=""
|
ENV IMMICH_API_TOKEN=""
|
||||||
ENV IMMICH_HOST=""
|
ENV IMMICH_HOST=""
|
||||||
ENV IMMICH_PORT=""
|
ENV IMMICH_PORT="8080"
|
||||||
#has to be EXPORT_PORT 8000 or else it does not work, same applies to the env file
|
#has to be EXPORT_PORT 8000 or else it does not work, same applies to the env file
|
||||||
ENV EXPORTER_PORT="8000"
|
ENV EXPORTER_PORT="8000"
|
||||||
ENV EXPORTER_LOG_LEVEL="INFO"
|
ENV EXPORTER_LOG_LEVEL="INFO"
|
||||||
|
|
23
README.md
23
README.md
|
@ -5,26 +5,14 @@ A prometheus exporter for Immich. Get metrics from a server and offers them in a
|
||||||
|
|
||||||
## How to use it
|
## How to use it
|
||||||
|
|
||||||
You can install this exporter with the following command:
|
Here is an example docker run command
|
||||||
|
|
||||||
```bash
|
|
||||||
pip3 install prometheus-qbittorrent-exporter
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you can run it with
|
|
||||||
|
|
||||||
```
|
```
|
||||||
immich-exporter
|
docker run -e IMMICH_PORT=8080 -e IMMICH_HOST=192.168.178.1 -e IMMICH_API_TOKEN=TOKEN -p 8000:8000 friendlyfriend/prometheus-immich-exporter
|
||||||
```
|
|
||||||
|
|
||||||
Another option is to run it in a docker container. Here is an example docker run command
|
|
||||||
|
|
||||||
```
|
|
||||||
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: "immich_exporter"
|
- job_name: "Immich_exporter"
|
||||||
static_configs:
|
static_configs:
|
||||||
- targets: ['yourimmichexporter:port']
|
- targets: ['yourimmichexporter:port']
|
||||||
```
|
```
|
||||||
|
@ -32,8 +20,9 @@ The application reads configuration using environment variables:
|
||||||
|
|
||||||
| Environment variable | Default | Description |
|
| Environment variable | Default | Description |
|
||||||
|----------------------|----------|----------------------------------------------------|
|
|----------------------|----------|----------------------------------------------------|
|
||||||
| `IMMICH_HOST` | | immich server hostname |
|
| `IMMICH_HOST` | | Immich proxy url |
|
||||||
| `IMMICH_PORT` | | immich server port |
|
| `IMMICH_PORT` | `8080` | Immich proxy port |
|
||||||
|
| `IMMICH_API_TOKEN` | | Immich API token, created from Immich dashboard |
|
||||||
| `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` | `immich` | Prefix to add to all the metrics |
|
| `METRICS_PREFIX` | `immich` | Prefix to add to all the metrics |
|
||||||
|
|
|
@ -199,7 +199,7 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "user count",
|
"title": "User count",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -261,7 +261,7 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "disk space used by Immich",
|
"title": "Disk space used by Immich",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -323,7 +323,7 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "total disk size",
|
"title": "Total disk size",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -385,7 +385,7 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "total disk size usage",
|
"title": "Total disk size usage",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -451,7 +451,7 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "remaining disk size",
|
"title": "Remaining disk size",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -484,7 +484,7 @@
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 3
|
"y": 3
|
||||||
},
|
},
|
||||||
"hideTimeOverride": true,
|
"hideTimeOverride": false,
|
||||||
"id": 24,
|
"id": 24,
|
||||||
"options": {
|
"options": {
|
||||||
"colorMode": "background",
|
"colorMode": "background",
|
||||||
|
@ -509,7 +509,7 @@
|
||||||
},
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"exemplar": false,
|
"exemplar": false,
|
||||||
"expr": "increase(immich_server_stats_usage_growth[24h])",
|
"expr": "increase(immich_server_stats_usage_growth[1d])",
|
||||||
"instant": false,
|
"instant": false,
|
||||||
"legendFormat": "__auto",
|
"legendFormat": "__auto",
|
||||||
"range": true,
|
"range": true,
|
||||||
|
@ -550,7 +550,7 @@
|
||||||
"x": 6,
|
"x": 6,
|
||||||
"y": 3
|
"y": 3
|
||||||
},
|
},
|
||||||
"hideTimeOverride": true,
|
"hideTimeOverride": false,
|
||||||
"id": 26,
|
"id": 26,
|
||||||
"options": {
|
"options": {
|
||||||
"colorMode": "background",
|
"colorMode": "background",
|
||||||
|
@ -574,13 +574,13 @@
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "${DS_PROMETHEUS}"
|
||||||
},
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"expr": "increase(immich_server_stats_useage_growth[7d])",
|
"expr": "increase(immich_server_stats_usage_growth[1w])",
|
||||||
"legendFormat": "__auto",
|
"legendFormat": "__auto",
|
||||||
"range": true,
|
"range": true,
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/w",
|
"timeFrom": "1w",
|
||||||
"title": "Weekly data growth",
|
"title": "Weekly data growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
|
@ -648,7 +648,7 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "disk usage by user",
|
"title": "Disk usage by user",
|
||||||
"type": "piechart"
|
"type": "piechart"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -681,7 +681,7 @@
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 7
|
"y": 7
|
||||||
},
|
},
|
||||||
"hideTimeOverride": true,
|
"hideTimeOverride": false,
|
||||||
"id": 28,
|
"id": 28,
|
||||||
"options": {
|
"options": {
|
||||||
"colorMode": "background",
|
"colorMode": "background",
|
||||||
|
@ -705,13 +705,13 @@
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "${DS_PROMETHEUS}"
|
||||||
},
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"expr": "increase(immich_server_stats_usage_growth[30h])",
|
"expr": "increase(immich_server_stats_usage_growth[4w])",
|
||||||
"legendFormat": "__auto",
|
"legendFormat": "__auto",
|
||||||
"range": true,
|
"range": true,
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/M",
|
"timeFrom": "1M",
|
||||||
"title": "Monthly data growth",
|
"title": "Monthly data growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
|
@ -745,7 +745,7 @@
|
||||||
"x": 6,
|
"x": 6,
|
||||||
"y": 7
|
"y": 7
|
||||||
},
|
},
|
||||||
"hideTimeOverride": true,
|
"hideTimeOverride": false,
|
||||||
"id": 30,
|
"id": 30,
|
||||||
"options": {
|
"options": {
|
||||||
"colorMode": "background",
|
"colorMode": "background",
|
||||||
|
@ -769,14 +769,14 @@
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "${DS_PROMETHEUS}"
|
||||||
},
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"expr": "increase(immich_server_stats_useage_growth[365d])",
|
"expr": "increase(immich_server_stats_usage_growth[1y])",
|
||||||
"legendFormat": "__auto",
|
"legendFormat": "__auto",
|
||||||
"range": true,
|
"range": true,
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/y",
|
"timeFrom": "1y",
|
||||||
"title": "Yealy data growth",
|
"title": "Yearly data growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -837,7 +837,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/d",
|
"timeFrom": "now/d",
|
||||||
"title": "daily photos growth",
|
"title": "Daily photos growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -897,8 +897,8 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/w",
|
"timeFrom": "1w",
|
||||||
"title": "weekly photos growth",
|
"title": "Weekly photos growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1029,7 +1029,7 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/M",
|
"timeFrom": "1M",
|
||||||
"title": "Monthly photos growth",
|
"title": "Monthly photos growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
|
@ -1086,14 +1086,14 @@
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "${DS_PROMETHEUS}"
|
||||||
},
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"expr": "increase(immich_server_stats_photos_growth[52w])",
|
"expr": "increase(immich_server_stats_photos_growth[1y])",
|
||||||
"legendFormat": "__auto",
|
"legendFormat": "__auto",
|
||||||
"range": true,
|
"range": true,
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/y",
|
"timeFrom": "1y",
|
||||||
"title": "yearly photos growth",
|
"title": "Yearly photos growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1160,7 +1160,7 @@
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 19
|
"y": 19
|
||||||
},
|
},
|
||||||
"hideTimeOverride": true,
|
"hideTimeOverride": false,
|
||||||
"id": 22,
|
"id": 22,
|
||||||
"options": {
|
"options": {
|
||||||
"legend": {
|
"legend": {
|
||||||
|
@ -1187,8 +1187,103 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/M",
|
"timeFrom": "1M",
|
||||||
"title": "Monthly Photos Growth",
|
"title": "Photos Growth",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "${DS_PROMETHEUS}"
|
||||||
|
},
|
||||||
|
"description": "amount of photos over time",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "right",
|
||||||
|
"axisSoftMin": 9000,
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 30,
|
||||||
|
"gradientMode": "opacity",
|
||||||
|
"hideFrom": {
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineStyle": {
|
||||||
|
"fill": "solid"
|
||||||
|
},
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 1,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 7,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 26
|
||||||
|
},
|
||||||
|
"hideTimeOverride": false,
|
||||||
|
"id": 47,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "${DS_PROMETHEUS}"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"expr": "immich_server_stats_photos_by_users",
|
||||||
|
"legendFormat": "{{firstName}}",
|
||||||
|
"range": true,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": "1y",
|
||||||
|
"title": "Photos Growth",
|
||||||
"type": "timeseries"
|
"type": "timeseries"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1206,8 +1301,7 @@
|
||||||
"mode": "absolute",
|
"mode": "absolute",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"color": "green",
|
"color": "green"
|
||||||
"value": null
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1218,7 +1312,7 @@
|
||||||
"h": 4,
|
"h": 4,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 26
|
"y": 33
|
||||||
},
|
},
|
||||||
"hideTimeOverride": true,
|
"hideTimeOverride": true,
|
||||||
"id": 42,
|
"id": 42,
|
||||||
|
@ -1251,7 +1345,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/d",
|
"timeFrom": "now/d",
|
||||||
"title": "daily video growth",
|
"title": "Daily video growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1269,8 +1363,7 @@
|
||||||
"mode": "absolute",
|
"mode": "absolute",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"color": "green",
|
"color": "green"
|
||||||
"value": null
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1281,7 +1374,7 @@
|
||||||
"h": 4,
|
"h": 4,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 6,
|
"x": 6,
|
||||||
"y": 26
|
"y": 33
|
||||||
},
|
},
|
||||||
"hideTimeOverride": true,
|
"hideTimeOverride": true,
|
||||||
"id": 40,
|
"id": 40,
|
||||||
|
@ -1313,8 +1406,8 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/w",
|
"timeFrom": "1w",
|
||||||
"title": "weekly videos growth",
|
"title": "Weekly videos growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1342,7 +1435,7 @@
|
||||||
"h": 8,
|
"h": 8,
|
||||||
"w": 12,
|
"w": 12,
|
||||||
"x": 12,
|
"x": 12,
|
||||||
"y": 26
|
"y": 33
|
||||||
},
|
},
|
||||||
"id": 6,
|
"id": 6,
|
||||||
"options": {
|
"options": {
|
||||||
|
@ -1381,7 +1474,7 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "videos",
|
"title": "Videos",
|
||||||
"type": "piechart"
|
"type": "piechart"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1410,7 +1503,7 @@
|
||||||
"h": 4,
|
"h": 4,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 30
|
"y": 37
|
||||||
},
|
},
|
||||||
"hideTimeOverride": true,
|
"hideTimeOverride": true,
|
||||||
"id": 44,
|
"id": 44,
|
||||||
|
@ -1428,7 +1521,7 @@
|
||||||
},
|
},
|
||||||
"textMode": "auto"
|
"textMode": "auto"
|
||||||
},
|
},
|
||||||
"pluginVersion": "9.4.3",
|
"pluginVersion": "10.0.2",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
|
@ -1442,7 +1535,7 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/M",
|
"timeFrom": "1M",
|
||||||
"title": "Monthly videos growth",
|
"title": "Monthly videos growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
|
@ -1472,7 +1565,7 @@
|
||||||
"h": 4,
|
"h": 4,
|
||||||
"w": 6,
|
"w": 6,
|
||||||
"x": 6,
|
"x": 6,
|
||||||
"y": 30
|
"y": 37
|
||||||
},
|
},
|
||||||
"hideTimeOverride": true,
|
"hideTimeOverride": true,
|
||||||
"id": 46,
|
"id": 46,
|
||||||
|
@ -1490,7 +1583,7 @@
|
||||||
},
|
},
|
||||||
"textMode": "auto"
|
"textMode": "auto"
|
||||||
},
|
},
|
||||||
"pluginVersion": "9.4.3",
|
"pluginVersion": "10.0.2",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
|
@ -1498,14 +1591,14 @@
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "${DS_PROMETHEUS}"
|
||||||
},
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"expr": "increase(immich_server_stats_videos_growth[52w])\r\n",
|
"expr": "increase(immich_server_stats_videos_growth[1y])\r\n",
|
||||||
"legendFormat": "__auto",
|
"legendFormat": "__auto",
|
||||||
"range": true,
|
"range": true,
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/y",
|
"timeFrom": "1y",
|
||||||
"title": "Panel Title",
|
"title": "Yearly video growth",
|
||||||
"type": "stat"
|
"type": "stat"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1568,7 +1661,7 @@
|
||||||
"h": 8,
|
"h": 8,
|
||||||
"w": 24,
|
"w": 24,
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 34
|
"y": 41
|
||||||
},
|
},
|
||||||
"id": 20,
|
"id": 20,
|
||||||
"options": {
|
"options": {
|
||||||
|
@ -1596,7 +1689,99 @@
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": "now/M",
|
"timeFrom": "1M",
|
||||||
|
"title": "Videos growth",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "${DS_PROMETHEUS}"
|
||||||
|
},
|
||||||
|
"description": "amount of videos over time",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "right",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 30,
|
||||||
|
"gradientMode": "opacity",
|
||||||
|
"hideFrom": {
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineStyle": {
|
||||||
|
"fill": "solid"
|
||||||
|
},
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 49
|
||||||
|
},
|
||||||
|
"id": 48,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "${DS_PROMETHEUS}"
|
||||||
|
},
|
||||||
|
"editorMode": "code",
|
||||||
|
"expr": "immich_server_stats_videos_by_users",
|
||||||
|
"legendFormat": "{{firstName}}",
|
||||||
|
"range": true,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": "1y",
|
||||||
"title": "Videos growth",
|
"title": "Videos growth",
|
||||||
"type": "timeseries"
|
"type": "timeseries"
|
||||||
}
|
}
|
||||||
|
@ -1617,6 +1802,6 @@
|
||||||
"timezone": "",
|
"timezone": "",
|
||||||
"title": "immich",
|
"title": "immich",
|
||||||
"uid": "ZWWp3aa4k",
|
"uid": "ZWWp3aa4k",
|
||||||
"version": 1,
|
"version": 9,
|
||||||
"weekStart": ""
|
"weekStart": ""
|
||||||
}
|
}
|
|
@ -39,6 +39,7 @@ class ImmichMetricsCollector:
|
||||||
yield prom_metric
|
yield prom_metric
|
||||||
|
|
||||||
def get_immich_metrics(self):
|
def get_immich_metrics(self):
|
||||||
|
|
||||||
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())
|
||||||
|
@ -47,6 +48,7 @@ class ImmichMetricsCollector:
|
||||||
|
|
||||||
return metrics
|
return metrics
|
||||||
|
|
||||||
|
|
||||||
def get_immich_users_stat_growth(self):
|
def get_immich_users_stat_growth(self):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -210,24 +212,27 @@ class ImmichMetricsCollector:
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_immich_server_version_number(self):
|
def get_immich_server_version_number(self):
|
||||||
|
# Requesting immich_server_number serves two purposes. As the name says it returns the version number
|
||||||
|
# 1. get version the full server version number
|
||||||
|
# 2. check if immich api key is correct
|
||||||
|
# throwing connectionRefused exception usually means that immich isn't running
|
||||||
|
|
||||||
server_version_endpoint = "/api/server-info/version"
|
server_version_endpoint = "/api/server-info/version"
|
||||||
response_server_version = ""
|
response_server_version = ""
|
||||||
|
|
||||||
for i in range(0, 360):
|
while True:
|
||||||
while True:
|
try:
|
||||||
try:
|
|
||||||
|
|
||||||
response_server_version = requests.request(
|
response_server_version = requests.request(
|
||||||
"GET",
|
"GET",
|
||||||
self.combine_url(server_version_endpoint),
|
self.combine_url(server_version_endpoint),
|
||||||
headers={'Accept': 'application/json',
|
headers={'Accept': 'application/json',
|
||||||
"x-api-key": self.config["token"]}
|
"x-api-key": self.config["token"]}
|
||||||
)
|
)
|
||||||
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")
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
|
|
||||||
server_version_number = (str(response_server_version.json()["major"]) + "." +
|
server_version_number = (str(response_server_version.json()["major"]) + "." +
|
||||||
str(response_server_version.json()["minor"]) + "." +
|
str(response_server_version.json()["minor"]) + "." +
|
||||||
|
@ -253,6 +258,7 @@ class ImmichMetricsCollector:
|
||||||
return combined_url
|
return combined_url
|
||||||
|
|
||||||
|
|
||||||
|
# test
|
||||||
class SignalHandler():
|
class SignalHandler():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.shutdownCount = 0
|
self.shutdownCount = 0
|
||||||
|
@ -284,6 +290,58 @@ def get_config_value(key, default=""):
|
||||||
return os.environ.get(key, default)
|
return os.environ.get(key, default)
|
||||||
|
|
||||||
|
|
||||||
|
def check_server_up(immichHost, immichPort):
|
||||||
|
|
||||||
|
#
|
||||||
|
counter = 0
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
counter = counter + 1
|
||||||
|
try:
|
||||||
|
|
||||||
|
requests.request(
|
||||||
|
"GET",
|
||||||
|
"http://" + immichHost + ":" + immichPort + "/api/server-info/ping",
|
||||||
|
headers={'Accept': 'application/json'}
|
||||||
|
)
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logger.error(f"CONNECTION ERROR. Cannot reach immich at " + immichHost + ":" + immichPort + "."
|
||||||
|
f"Is immich up and running?")
|
||||||
|
if 0 <= counter <= 60:
|
||||||
|
time.sleep(1)
|
||||||
|
elif 11 <= counter <= 300:
|
||||||
|
time.sleep(15)
|
||||||
|
elif counter > 300:
|
||||||
|
time.sleep(60)
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
logger.info(f"Found immich up and running at " + immichHost + ":" + immichPort + ".")
|
||||||
|
logger.info(f"Attempting to connect")
|
||||||
|
time.sleep(1)
|
||||||
|
logger.info("Exporter v1.0.6")
|
||||||
|
|
||||||
|
|
||||||
|
def check_immich_api_key(immichHost, immichPort, immichApiKey):
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
|
||||||
|
requests.request(
|
||||||
|
"GET",
|
||||||
|
"http://"+immichHost+":"+immichPort+"/api/server-info/",
|
||||||
|
headers={'Accept': 'application/json',
|
||||||
|
"x-api-key": immichApiKey}
|
||||||
|
)
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logger.error(f"CONNECTION ERROR. Possible API key error")
|
||||||
|
logger.error({e})
|
||||||
|
time.sleep(3)
|
||||||
|
continue
|
||||||
|
logger.info(f"Connected to immich successfully")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Init logger so it can be used
|
# Init logger so it can be used
|
||||||
logHandler = logging.StreamHandler()
|
logHandler = logging.StreamHandler()
|
||||||
|
@ -321,15 +379,21 @@ def main():
|
||||||
|
|
||||||
# Register our custom collector
|
# Register our custom collector
|
||||||
logger.info("Exporter is starting up")
|
logger.info("Exporter is starting up")
|
||||||
|
|
||||||
|
check_server_up(config["immich_host"], config["immich_port"])
|
||||||
|
check_immich_api_key(config["immich_host"], config["immich_port"], config["token"])
|
||||||
REGISTRY.register(ImmichMetricsCollector(config))
|
REGISTRY.register(ImmichMetricsCollector(config))
|
||||||
|
|
||||||
# Start server
|
# Start server
|
||||||
start_http_server(config["exporter_port"])
|
start_http_server(config["exporter_port"])
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Exporter listening on port {config['exporter_port']}"
|
f"Exporter listening on port {config['exporter_port']}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
while not signal_handler.is_shutting_down():
|
while not signal_handler.is_shutting_down():
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
logger.info("Exporter has shutdown")
|
logger.info("Exporter has shutdown")
|
||||||
|
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -6,7 +6,7 @@ with open("README.md", "r") as fh:
|
||||||
setup(
|
setup(
|
||||||
name='prometheus-immich-exporter',
|
name='prometheus-immich-exporter',
|
||||||
packages=['immich_exporter'],
|
packages=['immich_exporter'],
|
||||||
version='1.0.1',
|
version='1.0.6',
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
description='Prometheus exporter for immich',
|
description='Prometheus exporter for immich',
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
<PostArgs/>
|
<PostArgs/>
|
||||||
<CPUset/>
|
<CPUset/>
|
||||||
<DateInstalled>1678876858</DateInstalled>
|
<DateInstalled>1678876858</DateInstalled>
|
||||||
<DonateText>If I made your day a little bit brighter, consider donating.</DonateText>
|
<DonateText>If you like my work, consider supporting me.</DonateText>
|
||||||
<DonateLink>https://www.paypal.com/donate/?hosted_button_id=DPDKED3T3BFV8</DonateLink>
|
<DonateLink>https://www.paypal.com/donate/?hosted_button_id=DPDKED3T3BFV8</DonateLink>
|
||||||
<Requires/>
|
<Requires/>
|
||||||
<Config Name="Host Port 1" Target="8000" Default="8028" Mode="tcp" Description="" Type="Port" Display="always" Required="false" Mask="false">8028</Config>
|
<Config Name="Immich_exporter_port" Target="8000" Default="8000" Mode="tcp" Description="" Type="Port" Display="always" Required="false" Mask="false">8000</Config>
|
||||||
<Config Name="immich api token" Target="IMMICH_API_TOKEN" Default="" Mode="" Description="You need to log into to your immich admin account and create an api token in your settings" Type="Variable" Display="always" Required="false" Mask="false"/>
|
<Config Name="immich api token" Target="IMMICH_API_TOKEN" Default="" Mode="" Description="You need to log into to your immich admin account and create an api token in your settings" Type="Variable" Display="always" Required="false" Mask="false"/>
|
||||||
<Config Name="immich_host" Target="IMMICH_HOST" Default="" Mode="" Description="example: 192.168.178.2" Type="Variable" Display="always" Required="false" Mask="false"/>
|
<Config Name="immich_host" Target="IMMICH_HOST" Default="" Mode="" Description="Address to Immich_proxy, example: 192.168.178.2" Type="Variable" Display="always" Required="false" Mask="false"/>
|
||||||
<Config Name="immich port" Target="IMMICH_PORT" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false"/>
|
<Config Name="immich port" Target="IMMICH_PORT" Default="8080" Mode="" Description="Port for Immich_proxy" Type="Variable" Display="always" Required="false" Mask="false"/>
|
||||||
</Container>
|
</Container>
|
Loading…
Reference in a new issue