This commit is contained in:
2025-11-15 09:07:04 +01:00
commit d5834de32e
26 changed files with 2170 additions and 0 deletions

126
bin/snowpanel-collect.py Normal file
View File

@@ -0,0 +1,126 @@
#!/usr/bin/env python3
import json, subprocess, time, os, sys, math, shutil
from datetime import datetime, timezone, timedelta
STATE_DIR = "/var/lib/snowpanel"
STATS = os.path.join(STATE_DIR, "stats.json")
META = os.path.join(STATE_DIR, "meta.json")
CFG = "/etc/snowpanel/app.json"
def sh(cmd):
return subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True).stdout.strip()
def load_json(path, default):
try:
with open(path, "r") as f: return json.load(f)
except Exception:
return default
def save_json(path, obj):
tmp = path + ".tmp"
with open(tmp, "w") as f:
json.dump(obj, f, separators=(",", ":"), ensure_ascii=False)
os.replace(tmp, path)
def now():
return int(time.time())
def service_bytes():
out = sh(["/bin/systemctl","show","-p","IPIngressBytes","-p","IPEgressBytes","snowflake-proxy"])
rx = tx = 0
for line in out.splitlines():
if line.startswith("IPIngressBytes="):
try: rx = int(line.split("=",1)[1] or "0")
except: pass
elif line.startswith("IPEgressBytes="):
try: tx = int(line.split("=",1)[1] or "0")
except: pass
return rx, tx
def period_start_for_reset_day(reset_day: int) -> int:
reset_day = max(1, min(28, int(reset_day or 1)))
now_dt = datetime.now(timezone.utc).astimezone()
year = now_dt.year
month = now_dt.month
this_start = datetime(year, month, reset_day, 0, 0, 0, tzinfo=now_dt.tzinfo)
if now_dt >= this_start:
start = this_start
else:
if month == 1:
year -= 1; month = 12
else:
month -= 1
start = datetime(year, month, reset_day, 0, 0, 0, tzinfo=now_dt.tzinfo)
return int(start.timestamp())
def main():
os.makedirs(STATE_DIR, exist_ok=True)
rx, tx = service_bytes()
t = now()
stats = load_json(STATS, {"data":[]})
arr = stats.get("data", [])
arr.append({"t": t, "read": int(rx), "written": int(tx)})
if len(arr) > 5000:
arr = arr[-5000:]
stats["data"] = arr
save_json(STATS, stats)
cfg = load_json(CFG, {})
cap_gb = int(cfg.get("cap_gb", 0))
cap_reset_day = int(cfg.get("cap_reset_day", 1))
rate_mbps = int(cfg.get("rate_mbps", 0))
start_ts = period_start_for_reset_day(cap_reset_day)
rx_sum = 0
tx_sum = 0
prev = None
for point in arr:
if point["t"] < start_ts:
continue
if prev is not None:
dt = point["t"] - prev["t"]
if dt <= 0 or dt > 3600:
prev = point; continue
dr = max(0, point["read"] - prev["read"])
dw = max(0, point["written"] - prev["written"])
rx_sum += dr
tx_sum += dw
prev = point
total = rx_sum + tx_sum
cap_bytes = cap_gb * 1024 * 1024 * 1024 if cap_gb > 0 else 0
current_rate_mbps = 0.0
if len(arr) >= 2:
a = arr[-2]; b = arr[-1]
dt = max(1, b["t"] - a["t"])
dr = max(0, b["read"] - a["read"])
dw = max(0, b["written"] - a["written"])
current_rate_mbps = ((dr + dw) * 8.0) / dt / 1_000_000.0
label = datetime.fromtimestamp(start_ts).strftime("%Y-%m-%d") + f" (reset day {cap_reset_day})"
meta = {
"start_ts": start_ts,
"period_label": label,
"rx": rx_sum,
"tx": tx_sum,
"total": total,
"cap_bytes": cap_bytes,
"cap_hit": False,
"current_rate_mbps": current_rate_mbps,
"rate_mbps": rate_mbps
}
if cap_bytes and total >= cap_bytes:
meta["cap_hit"] = True
active = sh(["/bin/systemctl","is-active","snowflake-proxy"]) == "active"
if active:
subprocess.run(["/usr/bin/sudo","/bin/systemctl","stop","snowflake-proxy"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
save_json(META, meta)
if __name__ == "__main__":
main()