#!/usr/bin/env python3 """ LIFE Runtime Monitor Samlar operativa mätvärden under burn-in """ import sqlite3 import json import time from datetime import datetime, timedelta from pathlib import Path DB_PATH = "/home/bernt/.openclaw/workspace/rivp-pilot-1/rivp.db" LOG_DIR = Path("/home/bernt/.openclaw/workspace/life-weather/logs") METRICS_FILE = Path("/home/bernt/.openclaw/workspace/life-weather/metrics.json") def collect_metrics(): """Samla mätvärden från databasen""" conn = sqlite3.connect(DB_PATH) c = conn.cursor() metrics = { "timestamp": datetime.now().isoformat(), "pipeline": {}, "observations": {}, "system": {} } # Pipeline-mätvärden c.execute("SELECT COUNT(*) FROM weather_observations") total_obs = c.fetchone()[0] c.execute(""" SELECT COUNT(*) FROM weather_observations WHERE created_at > datetime('now', '-1 hour') """) obs_last_hour = c.fetchone()[0] # Dubbletter c.execute(""" SELECT road_id, observation_type, timestamp, COUNT(*) as cnt FROM weather_observations GROUP BY road_id, observation_type, timestamp HAVING cnt > 1 """) duplicates = len(c.fetchall()) # Reality Latency c.execute(""" SELECT MAX(created_at) FROM weather_observations """) last_obs = c.fetchone()[0] if last_obs: last_time = datetime.fromisoformat(last_obs) latency_minutes = (datetime.now() - last_time).total_seconds() / 60 else: latency_minutes = None metrics["observations"] = { "total": total_obs, "last_hour": obs_last_hour, "duplicates": duplicates, "reality_latency_minutes": round(latency_minutes, 1) if latency_minutes else None } # System-mätvärden (från loggar) log_file = LOG_DIR / "scheduler.log" if log_file.exists(): with open(log_file) as f: lines = f.readlines() # Räkna fel errors = [l for l in lines if "ERROR" in l] warnings = [l for l in lines if "WARNING" in l] metrics["pipeline"] = { "total_runs": len([l for l in lines if "WEATHER JOB STARTAR" in l]), "errors": len(errors), "warnings": len(warnings) } conn.close() # Spara mätvärden if METRICS_FILE.exists(): with open(METRICS_FILE) as f: history = json.load(f) else: history = [] history.append(metrics) # Behåll senaste 168 timmar (7 dagar) cutoff = datetime.now() - timedelta(hours=168) history = [h for h in history if datetime.fromisoformat(h["timestamp"]) > cutoff] with open(METRICS_FILE, 'w') as f: json.dump(history, f, indent=2) return metrics def print_status(): """Skriv ut aktuell status""" metrics = collect_metrics() print("=" * 60) print("LIFE RUNTIME STATUS") print("=" * 60) print(f"Tid: {metrics['timestamp']}") print() print("OBSERVATIONER:") print(f" Total: {metrics['observations']['total']}") print(f" Senaste timmen: {metrics['observations']['last_hour']}") print(f" Dubbletter: {metrics['observations']['duplicates']}") print(f" Reality Latency: {metrics['observations']['reality_latency_minutes']} min") print() print("PIPELINE:") print(f" Körningar: {metrics['pipeline'].get('total_runs', 0)}") print(f" Fel: {metrics['pipeline'].get('errors', 0)}") print(f" Varningar: {metrics['pipeline'].get('warnings', 0)}") print() # Beräkna success rate total = metrics['pipeline'].get('total_runs', 0) errors = metrics['pipeline'].get('errors', 0) if total > 0: success_rate = ((total - errors) / total) * 100 print(f" Success Rate: {success_rate:.1f}%") print("=" * 60) if __name__ == "__main__": print_status()