Some checks failed
Build and Deploy Log Center / build-and-deploy (push) Failing after 1m19s
- 新增 app/self_report.py:后端运行时异常直接写入自身数据库 - main.py:添加全局异常处理器 + 启动时注册 log_center_api/web 项目 - web/api.ts:添加 reportError 函数 + Axios 5xx 拦截器 - web/main.tsx:添加 window.onerror / onunhandledrejection 全局捕获 - deploy.yaml:CI/CD 流水线各步骤失败时上报(build/deploy) - 重写 integration_guide.md:按三类上报(runtime/cicd/deployment)重新组织 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
81 lines
3.0 KiB
Python
81 lines
3.0 KiB
Python
"""Log Center 自身错误上报:将 API 运行时异常写入自己的数据库。"""
|
||
import os
|
||
import sys
|
||
import traceback
|
||
import hashlib
|
||
from datetime import datetime
|
||
|
||
from sqlmodel import select
|
||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||
from sqlalchemy.orm import sessionmaker
|
||
|
||
from .database import engine
|
||
from .models import ErrorLog, LogStatus, Project
|
||
|
||
PROJECT_ID = "log_center_api"
|
||
ENVIRONMENT = os.getenv("ENVIRONMENT", "production")
|
||
|
||
|
||
async def self_report_error(exc: Exception, context: dict = None):
|
||
"""将 Log Center API 自身的异常写入数据库。
|
||
|
||
直接操作数据库而非走 HTTP,避免循环依赖和额外开销。
|
||
任何内部错误都静默处理,绝不影响主业务。
|
||
"""
|
||
try:
|
||
tb = traceback.extract_tb(exc.__traceback__)
|
||
last_frame = tb[-1] if tb else None
|
||
|
||
error_type = type(exc).__name__
|
||
file_path = last_frame.filename if last_frame else "unknown"
|
||
line_number = last_frame.lineno if last_frame else 0
|
||
stack_trace = traceback.format_exception(exc)
|
||
|
||
# 生成指纹(与 main.py 中 runtime 类型的逻辑一致)
|
||
raw = f"{PROJECT_ID}|{error_type}|{file_path}|{line_number}"
|
||
fingerprint = hashlib.md5(raw.encode()).hexdigest()
|
||
|
||
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||
async with async_session() as session:
|
||
# 去重检查
|
||
stmt = select(ErrorLog).where(ErrorLog.fingerprint == fingerprint)
|
||
result = await session.exec(stmt)
|
||
existing = result.first()
|
||
|
||
if existing:
|
||
if existing.status not in [LogStatus.DEPLOYED, LogStatus.FIXED, LogStatus.VERIFIED]:
|
||
return # 已在追踪中,跳过
|
||
# 回归:已修复的错误再次出现
|
||
existing.status = LogStatus.NEW
|
||
existing.timestamp = datetime.utcnow()
|
||
existing.retry_count = 0
|
||
session.add(existing)
|
||
await session.commit()
|
||
return
|
||
|
||
# 确保 project 记录存在
|
||
proj_stmt = select(Project).where(Project.project_id == PROJECT_ID)
|
||
proj_result = await session.exec(proj_stmt)
|
||
if not proj_result.first():
|
||
session.add(Project(project_id=PROJECT_ID, name="Log Center API"))
|
||
|
||
new_log = ErrorLog(
|
||
project_id=PROJECT_ID,
|
||
environment=ENVIRONMENT,
|
||
level="ERROR",
|
||
source="runtime",
|
||
error_type=error_type,
|
||
error_message=str(exc),
|
||
file_path=file_path,
|
||
line_number=line_number,
|
||
stack_trace=stack_trace,
|
||
context=context or {},
|
||
fingerprint=fingerprint,
|
||
timestamp=datetime.utcnow(),
|
||
)
|
||
session.add(new_log)
|
||
await session.commit()
|
||
except Exception:
|
||
# 自身上报绝不能导致服务崩溃
|
||
traceback.print_exc(file=sys.stderr)
|