import hashlib import logging import traceback import threading from django.utils import timezone class DatabaseErrorHandler(logging.Handler): def __init__(self, level=logging.ERROR): super().__init__(level) def emit(self, record): if not record.exc_info and record.levelno < logging.ERROR: return def _save(): try: from .models import ErrorLog exception_type = '' tb_string = '' if record.exc_info: exception_type = record.exc_info[0].__name__ if record.exc_info[0] else '' tb_string = ''.join(traceback.format_exception(*record.exc_info)) hash_input = f"{exception_type}:{record.module}:{record.funcName}:{record.lineno}" hash_key = hashlib.md5(hash_input.encode()).hexdigest() request = None user = None ip_address = None path = '' request_data = '' from django.core.handlers.wsgi import WSGIRequest from django.core.handlers.asgi import ASGIRequest if hasattr(record, 'request'): request = record.request elif hasattr(record, 'args') and record.args: for arg in record.args: if isinstance(arg, (WSGIRequest, ASGIRequest)): request = arg break if request: try: if hasattr(request, 'user') and request.user.is_authenticated: user = request.user except Exception: pass ip_address = _get_ip(request) path = getattr(request, 'path', '') existing = ErrorLog.objects.filter(hash_key=hash_key).first() if existing: existing.occurrence_count += 1 existing.timestamp = timezone.now() existing.save(update_fields=['occurrence_count', 'timestamp']) else: ErrorLog.objects.create( level=record.levelname, message=record.getMessage()[:1000], module=record.module, function=record.funcName, line_number=record.lineno, exception_type=exception_type, traceback=tb_string, user=user, ip_address=ip_address, path=path, request_data=request_data, hash_key=hash_key, ) except Exception: pass thread = threading.Thread(target=_save) thread.daemon = True thread.start() def _get_ip(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: return x_forwarded_for.split(',')[0].strip() return request.META.get('REMOTE_ADDR')