Files
workspace/tools/sysmon.py

238 lines
6.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""
sysmon - System monitor
Quick system status and resource tracking.
"""
import os
import json
import subprocess
from datetime import datetime
from pathlib import Path
WORKSPACE = Path("/home/wdjones/.openclaw/workspace")
HISTORY_FILE = WORKSPACE / "data" / "sysmon_history.json"
def get_cpu_usage():
"""Get CPU usage percentage."""
try:
# Read /proc/stat for CPU usage
with open('/proc/stat') as f:
line = f.readline()
parts = line.split()
idle = int(parts[4])
total = sum(int(p) for p in parts[1:])
# Read again after a moment
import time
time.sleep(0.1)
with open('/proc/stat') as f:
line = f.readline()
parts = line.split()
idle2 = int(parts[4])
total2 = sum(int(p) for p in parts[1:])
idle_delta = idle2 - idle
total_delta = total2 - total
if total_delta == 0:
return 0
usage = 100 * (1 - idle_delta / total_delta)
return round(usage, 1)
except:
return None
def get_memory():
"""Get memory usage."""
try:
with open('/proc/meminfo') as f:
lines = f.readlines()
mem = {}
for line in lines:
parts = line.split()
key = parts[0].rstrip(':')
value = int(parts[1]) # in KB
mem[key] = value
total = mem.get('MemTotal', 0) / 1024 / 1024 # GB
available = mem.get('MemAvailable', 0) / 1024 / 1024 # GB
used = total - available
pct = (used / total * 100) if total > 0 else 0
return {
'total_gb': round(total, 1),
'used_gb': round(used, 1),
'available_gb': round(available, 1),
'percent': round(pct, 1),
}
except:
return None
def get_disk():
"""Get disk usage."""
try:
stat = os.statvfs('/')
total = stat.f_blocks * stat.f_frsize / 1024 / 1024 / 1024 # GB
free = stat.f_bavail * stat.f_frsize / 1024 / 1024 / 1024 # GB
used = total - free
pct = (used / total * 100) if total > 0 else 0
return {
'total_gb': round(total, 1),
'used_gb': round(used, 1),
'free_gb': round(free, 1),
'percent': round(pct, 1),
}
except:
return None
def get_load():
"""Get system load average."""
try:
with open('/proc/loadavg') as f:
parts = f.read().split()
return {
'load1': float(parts[0]),
'load5': float(parts[1]),
'load15': float(parts[2]),
}
except:
return None
def get_uptime():
"""Get system uptime."""
try:
with open('/proc/uptime') as f:
uptime_seconds = float(f.read().split()[0])
days = int(uptime_seconds // 86400)
hours = int((uptime_seconds % 86400) // 3600)
mins = int((uptime_seconds % 3600) // 60)
if days > 0:
return f"{days}d {hours}h {mins}m"
elif hours > 0:
return f"{hours}h {mins}m"
else:
return f"{mins}m"
except:
return None
def get_processes():
"""Get top processes by memory/CPU."""
try:
result = subprocess.run(
['ps', 'aux', '--sort=-rss'],
capture_output=True, text=True
)
lines = result.stdout.strip().split('\n')[1:6] # Skip header, top 5
processes = []
for line in lines:
parts = line.split(None, 10)
if len(parts) >= 11:
processes.append({
'user': parts[0],
'cpu': float(parts[2]),
'mem': float(parts[3]),
'cmd': parts[10][:30],
})
return processes
except:
return []
def bar(pct: float, width: int = 20) -> str:
"""Create a progress bar."""
filled = int(pct / 100 * width)
return "" * filled + "" * (width - filled)
def show_status():
"""Show current system status."""
print()
print("" + "" * 40 + "")
print(f"║ 🖥️ System Monitor {' ' * 20}")
print("" + "" * 40 + "")
# Uptime
uptime = get_uptime()
if uptime:
print(f"\n⏰ Uptime: {uptime}")
# CPU
cpu = get_cpu_usage()
if cpu is not None:
print(f"\n🔲 CPU: {bar(cpu)} {cpu}%")
# Memory
mem = get_memory()
if mem:
print(f"🔲 Memory: {bar(mem['percent'])} {mem['percent']}%")
print(f" {mem['used_gb']:.1f}GB / {mem['total_gb']:.1f}GB")
# Disk
disk = get_disk()
if disk:
print(f"🔲 Disk: {bar(disk['percent'])} {disk['percent']}%")
print(f" {disk['used_gb']:.0f}GB / {disk['total_gb']:.0f}GB")
# Load
load = get_load()
if load:
print(f"\n📊 Load: {load['load1']:.2f} / {load['load5']:.2f} / {load['load15']:.2f}")
# Top processes
procs = get_processes()
if procs:
print(f"\n🔝 Top Processes:")
for p in procs[:3]:
print(f" {p['mem']:.1f}% {p['cmd']}")
print()
def record():
"""Record current stats to history."""
HISTORY_FILE.parent.mkdir(parents=True, exist_ok=True)
if HISTORY_FILE.exists():
with open(HISTORY_FILE) as f:
history = json.load(f)
else:
history = []
entry = {
'timestamp': datetime.now().isoformat(),
'cpu': get_cpu_usage(),
'memory': get_memory(),
'disk': get_disk(),
'load': get_load(),
}
history.append(entry)
# Keep last 1000 entries
history = history[-1000:]
with open(HISTORY_FILE, 'w') as f:
json.dump(history, f)
print(f"✓ Recorded at {entry['timestamp'][:19]}")
def main():
import sys
if len(sys.argv) > 1:
cmd = sys.argv[1]
if cmd == 'record':
record()
else:
print("Usage: sysmon [record]")
else:
show_status()
if __name__ == "__main__":
main()