Files
openclaw/scripts/collect_usage.py
Clawd BotandClaude Opus 4.6 ca9b510922 chore: align with upstream openclaw/openclaw and overlay local additions
- Reset master to upstream/main (16,697 commits)
- Overlay 2,271 local-only files (skills, tools, workspace, configs, apps)
- Restore IDENTITY.md and USER.md templates
- Build verified, gateway running, Discord working

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-03 07:40:46 +01:00

126 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""collect_usage.py
Collects usage & health metrics from configured providers and logs into SQLite.
Runs safely without sudo; writes DB to /home/alex/clawd/data/usage.db
"""
import os
import sqlite3
import time
import json
import subprocess
from datetime import datetime
DB_DIR = os.path.expanduser('~/clawd/data')
DB_PATH = os.path.join(DB_DIR, 'usage.db')
LOG_PATH = '/var/log/openclaw/usage.log'
os.makedirs(DB_DIR, exist_ok=True)
def init_db(conn):
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS metrics (
ts INTEGER,
provider TEXT,
metric TEXT,
value REAL,
raw TEXT
)''')
conn.commit()
def insert(conn, provider, metric, value, raw=None):
c = conn.cursor()
c.execute('INSERT INTO metrics (ts,provider,metric,value,raw) VALUES (?,?,?,?,?)',
(int(time.time()), provider, metric, value or 0.0, json.dumps(raw) if raw is not None else None))
conn.commit()
def check_ollama():
try:
out = subprocess.check_output(['curl','-sS','http://192.168.1.144:11434/api/tags'], timeout=10)
j = json.loads(out)
models = len(j.get('models', []))
return True, {'models': models}
except Exception as e:
return False, {'error': str(e)}
def check_nvidia():
# call nvidia_api.py health if available
script = os.path.expanduser('~/clawd/skills/nvidia-agent/scripts/nvidia_api.py')
if os.path.exists(script):
try:
out = subprocess.check_output([script,'health'], timeout=20)
j = json.loads(out.decode())
return True, j
except Exception as e:
return False, {'error': str(e)}
return None, None
def check_logs_for_rate_limits(window_minutes=30):
res = []
cutoff = time.time() - (window_minutes*60)
if os.path.exists(LOG_PATH):
try:
with open(LOG_PATH,'r') as f:
for line in f:
# Expect ISO timestamp at start
if not line.strip():
continue
try:
ts_part = line.split()[0]
try:
ts = datetime.fromisoformat(ts_part).timestamp()
except Exception:
ts = None
except Exception:
ts = None
if ts and ts < cutoff:
continue
if 'rate_limit' in line or '429' in line or 'RESOURCE_EXHAUSTED' in line:
res.append(line.strip())
except Exception:
pass
return res
def main():
conn = sqlite3.connect(DB_PATH)
init_db(conn)
# Ollama
ok, data = check_ollama()
if ok:
insert(conn, 'ollama', 'models_count', data.get('models',0), data)
else:
insert(conn, 'ollama', 'up', 0, data)
# NVIDIA
ok, data = check_nvidia()
if ok is True:
insert(conn, 'nvidia', 'models_count', data.get('models_count',0), data)
elif ok is False:
insert(conn, 'nvidia', 'up', 0, data)
# Logs rate limits
rl = check_logs_for_rate_limits(30)
insert(conn, 'logs', 'rate_limit_hits_30m', len(rl), {'lines': rl[:10]})
# Optionally OpenAI admin cost (if key present)
admin_key_path = os.path.expanduser('~/.openclaw/credentials/openai-admin.key')
if os.path.exists(admin_key_path):
try:
key = open(admin_key_path).read().strip()
import requests
r = requests.get('https://api.openai.com/v1/usage', headers={'Authorization': f'Bearer {key}'}, timeout=10)
if r.status_code == 200:
js = r.json()
# placeholder parsing
insert(conn, 'openai', 'admin_raw_ok', 1, js)
else:
insert(conn, 'openai', 'admin_ok', 0, {'status': r.status_code, 'body': r.text})
except Exception as e:
insert(conn, 'openai', 'admin_ok', 0, {'error': str(e)})
conn.close()
if __name__ == '__main__':
main()