Files
Bentlybro d508936556 Add error tracking and reporting to admin and API
Introduces an in-memory error tracker service for monitoring and debugging. Integrates error tracking into API and moderation logic, logs errors with details, and displays error statistics and recent errors in the admin system health page for improved visibility and diagnostics.
2025-10-02 20:07:59 +01:00

104 lines
3.4 KiB
Python

"""
In-memory error tracking for system health monitoring
"""
import time
from collections import deque
from threading import Lock
from typing import Dict, List
class ErrorTracker:
"""Track recent errors for monitoring and debugging"""
# Shared error tracking across all instances
_recent_errors = deque(maxlen=100) # Keep last 100 errors
_error_counts = {
'database': 0,
'processing': 0,
'api': 0,
'moderation': 0,
'other': 0
}
_lock = Lock()
@classmethod
def track_error(cls, error_type: str, message: str, content_id: str = None, details: Dict = None):
"""
Track an error occurrence
Args:
error_type: Type of error (database, processing, api, moderation, other)
message: Error message
content_id: Optional content ID associated with error
details: Optional additional details
"""
with cls._lock:
error_entry = {
'timestamp': time.time(),
'type': error_type,
'message': message,
'content_id': content_id,
'details': details or {}
}
cls._recent_errors.append(error_entry)
# Increment error type counter
if error_type in cls._error_counts:
cls._error_counts[error_type] += 1
else:
cls._error_counts['other'] += 1
@classmethod
def get_recent_errors(cls, limit: int = 50) -> List[Dict]:
"""Get recent errors with optional limit"""
with cls._lock:
# Convert deque to list and get last N items
errors = list(cls._recent_errors)[-limit:]
# Add human-readable timestamps
for error in errors:
seconds_ago = int(time.time() - error['timestamp'])
if seconds_ago < 60:
error['time_ago'] = f"{seconds_ago}s ago"
elif seconds_ago < 3600:
error['time_ago'] = f"{seconds_ago // 60}m ago"
else:
error['time_ago'] = f"{seconds_ago // 3600}h ago"
return errors
@classmethod
def get_error_counts(cls) -> Dict[str, int]:
"""Get error counts by type"""
with cls._lock:
return cls._error_counts.copy()
@classmethod
def get_error_stats(cls) -> Dict:
"""Get comprehensive error statistics"""
with cls._lock:
total_errors = sum(cls._error_counts.values())
recent_count = len(cls._recent_errors)
# Count errors in last 5 minutes
five_min_ago = time.time() - 300
recent_5min = sum(1 for e in cls._recent_errors if e['timestamp'] > five_min_ago)
return {
'total_errors': total_errors,
'recent_errors': recent_count,
'errors_last_5min': recent_5min,
'error_counts': cls._error_counts.copy()
}
@classmethod
def clear_old_errors(cls, max_age_seconds: int = 3600):
"""Clear errors older than specified age (default 1 hour)"""
with cls._lock:
cutoff_time = time.time() - max_age_seconds
# Keep only recent errors
while cls._recent_errors and cls._recent_errors[0]['timestamp'] < cutoff_time:
cls._recent_errors.popleft()
# Create singleton instance
error_tracker = ErrorTracker()