log-center/app/self_report.py
2026-03-18 16:23:05 +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 get_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(get_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)