Skip to content

Commit 706d1a3

Browse files
author
Joshua Most
committed
Add tools/backfill_openmetrics.py to backfill historical cumulative data via OpenMetrics
1 parent 5435f5a commit 706d1a3

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

tools/backfill_openmetrics.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import os
2+
import sys
3+
import time
4+
from collections import defaultdict
5+
from datetime import datetime
6+
import requests
7+
8+
9+
def iso_date(dt_str: str) -> str:
10+
return dt_str.split("T")[0]
11+
12+
13+
def fetch_radarr_movies(url: str, api_key: str):
14+
r = requests.get(f"{url}/api/v3/movie", headers={"X-Api-Key": api_key}, timeout=30)
15+
r.raise_for_status()
16+
return r.json()
17+
18+
19+
def fetch_sonarr_series(url: str, api_key: str):
20+
r = requests.get(f"{url}/api/v3/series", headers={"X-Api-Key": api_key}, timeout=30)
21+
r.raise_for_status()
22+
return r.json()
23+
24+
25+
def build_cumulative_by_date_radarr(movies):
26+
date_counts = defaultdict(int)
27+
for m in movies:
28+
added = m.get("added")
29+
if added:
30+
date_counts[iso_date(added)] += 1
31+
total = 0
32+
out = [] # list of (date_str, value)
33+
for d in sorted(date_counts.keys()):
34+
total += date_counts[d]
35+
out.append((d, total))
36+
return out
37+
38+
39+
def build_cumulative_by_date_sonarr(series):
40+
date_counts = defaultdict(int)
41+
for s in series:
42+
added = s.get("added")
43+
ep_files = s.get("statistics", {}).get("episodeFileCount", 0)
44+
if added and ep_files > 0:
45+
date_counts[iso_date(added)] += ep_files
46+
total = 0
47+
out = []
48+
for d in sorted(date_counts.keys()):
49+
total += date_counts[d]
50+
out.append((d, total))
51+
return out
52+
53+
54+
def to_unix_ms(date_str: str) -> int:
55+
# Interpret date as UTC midnight
56+
dt = datetime.strptime(date_str, "%Y-%m-%d")
57+
return int(time.mktime(dt.timetuple()) * 1000)
58+
59+
60+
def write_openmetrics(radarr_series, sonarr_series, fp):
61+
fp.write("# TYPE radarr_cumulative_movies gauge\n")
62+
for d, v in radarr_series:
63+
fp.write(f"radarr_cumulative_movies {v} {to_unix_ms(d)}\n")
64+
fp.write("\n")
65+
66+
fp.write("# TYPE sonarr_cumulative_episodes gauge\n")
67+
for d, v in sonarr_series:
68+
fp.write(f"sonarr_cumulative_episodes {v} {to_unix_ms(d)}\n")
69+
fp.write("\n# EOF\n")
70+
71+
72+
def main():
73+
radarr_url = os.getenv("RADARR_URL")
74+
radarr_api = os.getenv("RADARR_API_KEY")
75+
sonarr_url = os.getenv("SONARR_URL")
76+
sonarr_api = os.getenv("SONARR_API_KEY")
77+
78+
if not radarr_url or not radarr_api:
79+
print("Missing RADARR_URL or RADARR_API_KEY", file=sys.stderr)
80+
sys.exit(2)
81+
82+
movies = fetch_radarr_movies(radarr_url.rstrip("/"), radarr_api)
83+
radarr_series = build_cumulative_by_date_radarr(movies)
84+
85+
sonarr_series = []
86+
if sonarr_url and sonarr_api:
87+
series = fetch_sonarr_series(sonarr_url.rstrip("/"), sonarr_api)
88+
sonarr_series = build_cumulative_by_date_sonarr(series)
89+
90+
out_path = os.getenv("BACKFILL_OUT", "backfill.om")
91+
with open(out_path, "w", encoding="utf-8") as fp:
92+
write_openmetrics(radarr_series, sonarr_series, fp)
93+
94+
print(f"Wrote OpenMetrics backfill file: {out_path}")
95+
print("Next steps (Prometheus >= 2.40):")
96+
print("1) Stop Prometheus")
97+
print("2) Create blocks from OpenMetrics:")
98+
print(" promtool tsdb create-blocks-from openmetrics backfill.om ./backfill-blocks")
99+
print("3) Move generated blocks into Prometheus data dir (e.g., /var/lib/prometheus)")
100+
print("4) Start Prometheus")
101+
102+
103+
if __name__ == "__main__":
104+
main()

0 commit comments

Comments
 (0)