video-shuoshan/backend/utils/log_center.py
zyc 566c3a476f
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m17s
add 存储桶
2026-03-13 15:38:08 +08:00

80 lines
2.6 KiB
Python

"""Log Center integration — runtime error reporting."""
import os
import json
import traceback
import threading
from urllib.request import Request, urlopen
from urllib.error import URLError
LOG_CENTER_URL = os.getenv('LOG_CENTER_URL', 'https://qiyuan-log-center-api.airlabs.art')
LOG_CENTER_ENABLED = os.getenv('LOG_CENTER_ENABLED', 'false').lower() in ('true', '1', 'yes')
PROJECT_ID = 'video_backend'
ENVIRONMENT = os.getenv('ENVIRONMENT', 'development')
def report_error(exc, context=None):
"""Report a runtime error to Log Center (async, non-blocking)."""
if not LOG_CENTER_ENABLED:
return
tb = traceback.extract_tb(exc.__traceback__)
last_frame = tb[-1] if tb else None
payload = {
'project_id': PROJECT_ID,
'environment': ENVIRONMENT,
'level': 'ERROR',
'error': {
'type': type(exc).__name__,
'message': str(exc),
'file_path': last_frame.filename if last_frame else 'unknown',
'line_number': last_frame.lineno if last_frame else 0,
'stack_trace': ''.join(traceback.format_exception(exc)),
},
'context': context or {},
}
# Fire-and-forget in background thread
threading.Thread(target=_send, args=(payload,), daemon=True).start()
def _send(payload):
"""Send payload to Log Center API."""
try:
data = json.dumps(payload).encode('utf-8')
req = Request(
f'{LOG_CENTER_URL}/api/v1/logs/report',
data=data,
headers={'Content-Type': 'application/json'},
method='POST',
)
urlopen(req, timeout=3)
except (URLError, Exception):
pass # Silent failure — never affect main business
def custom_exception_handler(exc, context):
"""DRF custom exception handler with Log Center reporting."""
from rest_framework.views import exception_handler
from rest_framework.exceptions import (
MethodNotAllowed, NotAuthenticated, AuthenticationFailed,
NotFound, PermissionDenied,
)
# Only report unexpected errors, skip normal HTTP client errors
if not isinstance(exc, (MethodNotAllowed, NotAuthenticated,
AuthenticationFailed, NotFound,
PermissionDenied)):
request = context.get('request')
report_error(exc, {
'view': str(context.get('view', '')),
'request_path': getattr(request, 'path', None),
'request_method': getattr(request, 'method', None),
'user': str(getattr(request, 'user', 'anonymous')),
})
# Default DRF handling
response = exception_handler(exc, context)
return response