jaeswift-website/api/telemetry_snapshot.py

101 lines
3 KiB
Python

#!/usr/bin/env python3
"""Telemetry ring-buffer snapshot — runs every 5min via cron.
Appends system metrics to telemetry_history.json (288 points = 24h).
"""
import json, os, time, subprocess
from datetime import datetime, timezone
from pathlib import Path
DATA_DIR = Path(__file__).parent / 'data'
HISTORY_FILE = DATA_DIR / 'telemetry_history.json'
STATE_FILE = DATA_DIR / 'telemetry_netstate.json'
MAX_POINTS = 288 # 24h @ 5min
def shell(cmd, timeout=5):
try:
r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout)
return r.stdout.strip()
except Exception:
return ''
def gather():
load = shell("cat /proc/loadavg | awk '{print $1}'")
ncpu = shell("nproc")
try:
cpu = round(min(float(load) / max(int(ncpu), 1) * 100, 100), 1)
except Exception:
cpu = 0
mem = shell("free | awk '/Mem:/{printf \"%.1f\", $3/$2*100}'")
try:
mem = float(mem)
except Exception:
mem = 0
net_raw = shell("cat /proc/net/dev | awk '/eth0|ens|enp/{print $2,$10; exit}'")
parts = net_raw.split()
rx = int(parts[0]) if len(parts) >= 2 else 0
tx = int(parts[1]) if len(parts) >= 2 else 0
# Rate calc from previous state
prev = {}
if STATE_FILE.exists():
try:
prev = json.loads(STATE_FILE.read_text())
except Exception:
prev = {}
now = time.time()
rx_bps = tx_bps = 0
if prev.get('ts') and now > prev['ts']:
dt = now - prev['ts']
rx_bps = max(0, int((rx - prev.get('rx', 0)) / dt))
tx_bps = max(0, int((tx - prev.get('tx', 0)) / dt))
STATE_FILE.write_text(json.dumps({'rx': rx, 'tx': tx, 'ts': now}))
return {
'cpu': cpu,
'mem': mem,
'net_rx': rx_bps,
'net_tx': tx_bps,
'ts': datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ'),
}
def append_history(point):
data = {'cpu': [], 'mem': [], 'net_rx': [], 'net_tx': [], 'timestamps': []}
if HISTORY_FILE.exists():
try:
data = json.loads(HISTORY_FILE.read_text())
# Ensure all keys exist
for k in ('cpu', 'mem', 'net_rx', 'net_tx', 'timestamps'):
data.setdefault(k, [])
except Exception:
pass
data['cpu'].append(point['cpu'])
data['mem'].append(point['mem'])
data['net_rx'].append(point['net_rx'])
data['net_tx'].append(point['net_tx'])
data['timestamps'].append(point['ts'])
# Ring buffer trim
for k in ('cpu', 'mem', 'net_rx', 'net_tx', 'timestamps'):
if len(data[k]) > MAX_POINTS:
data[k] = data[k][-MAX_POINTS:]
DATA_DIR.mkdir(parents=True, exist_ok=True)
HISTORY_FILE.write_text(json.dumps(data))
if __name__ == '__main__':
try:
point = gather()
append_history(point)
print(f"[{point['ts']}] cpu={point['cpu']}% mem={point['mem']}% rx={point['net_rx']}bps tx={point['net_tx']}bps")
except Exception as e:
print(f"[ERROR] {e}")
raise