""" HuggingFace Spaces Debug Helper ================================ Adds real-time error logging and debug endpoints for easier debugging without rebuilding Docker every time. """ import sys import io import traceback import logging from datetime import datetime from pathlib import Path from collections import deque from threading import Lock class DebugLogger: """ Captures all errors and prints them both to console and stores them for viewing via web dashboard /debug endpoint. """ def __init__(self, max_errors=100, log_file="/home/user/app/logs/debug.log"): self.errors = deque(maxlen=max_errors) self.lock = Lock() self.log_file = Path(log_file) self.log_file.parent.mkdir(parents=True, exist_ok=True) # Set up file logging self.file_handler = logging.FileHandler(self.log_file) self.file_handler.setLevel(logging.ERROR) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') self.file_handler.setFormatter(formatter) # Add to root logger logging.getLogger().addHandler(self.file_handler) def log_error(self, error_type, error_msg, tb_str=None): """Log an error with timestamp and traceback""" timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") error_entry = { 'timestamp': timestamp, 'type': error_type, 'message': str(error_msg), 'traceback': tb_str or '' } with self.lock: self.errors.append(error_entry) # Print to console (HuggingFace captures this) print(f"\n{'='*80}") print(f"🔴 ERROR CAPTURED: {timestamp}") print(f"{'='*80}") print(f"Type: {error_type}") print(f"Message: {error_msg}") if tb_str: print(f"\nTraceback:") print(tb_str) print(f"{'='*80}\n") # Write to file with open(self.log_file, 'a') as f: f.write(f"\n{'='*80}\n") f.write(f"ERROR: {timestamp}\n") f.write(f"Type: {error_type}\n") f.write(f"Message: {error_msg}\n") if tb_str: f.write(f"Traceback:\n{tb_str}\n") f.write(f"{'='*80}\n") def get_recent_errors(self, count=20): """Get the most recent N errors""" with self.lock: return list(self.errors)[-count:] def get_all_errors(self): """Get all stored errors""" with self.lock: return list(self.errors) def clear_errors(self): """Clear all stored errors""" with self.lock: self.errors.clear() print("✅ Debug error log cleared") def get_log_file_contents(self): """Read the debug log file""" try: if self.log_file.exists(): with open(self.log_file, 'r') as f: return f.read() return "No debug log file found" except Exception as e: return f"Error reading log file: {e}" # Global debug logger instance debug_logger = DebugLogger() def capture_exception(func): """ Decorator to capture and log exceptions from any function """ def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as e: error_type = type(e).__name__ error_msg = str(e) tb_str = traceback.format_exc() debug_logger.log_error(error_type, error_msg, tb_str) raise # Re-raise the exception return wrapper def add_debug_routes(app): """ Add debug routes to Flask app Usage: from debug_helper import add_debug_routes add_debug_routes(app) """ @app.route('/debug') def debug_page(): """HTML page showing recent errors""" errors = debug_logger.get_all_errors() html = """
Real-time error monitoring for HuggingFace Spaces
{log_contents}
"""
print("✅ Debug routes added: /debug, /debug/clear, /debug/logs")
def patch_quantum_meta_controller():
"""
Monkey-patch the QuantumMetaController to use debug logging
Call this before creating the controller instance
"""
print("🔧 Patching QuantumMetaController for better error logging...")
# This will be imported dynamically
import types
def patched_run_with_cleanup(original_func):
def wrapper(*args, **kwargs):
try:
return original_func(*args, **kwargs)
except Exception as e:
error_type = type(e).__name__
error_msg = str(e)
tb_str = traceback.format_exc()
debug_logger.log_error(error_type, error_msg, tb_str)
# Store in container
if len(args) > 0 and isinstance(args[0], dict):
args[0]['error'] = e
raise
return wrapper
print("✅ QuantumMetaController patched for debug logging")
if __name__ == "__main__":
# Test the debug logger
print("Testing debug logger...")
try:
raise ValueError("This is a test error")
except Exception as e:
debug_logger.log_error(
type(e).__name__,
str(e),
traceback.format_exc()
)
print(f"\nCaptured {len(debug_logger.get_all_errors())} errors")
print("\nRecent errors:")
for error in debug_logger.get_recent_errors():
print(f" - {error['timestamp']}: {error['type']} - {error['message']}")