#!/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