log-center/app/self_report.py
zyc c8204b6d47
Some checks failed
Build and Deploy Log Center / build-and-deploy (push) Failing after 1m19s
feat(self-report): 日志中台自身接入错误上报
- 新增 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>
2026-02-26 10:08:26 +08:00

81 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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