Files
chunyu_project/logs/handlers.py
T
2026-08-05 23:59:15 +08:00

87 lines
3.1 KiB
Python

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')