import time import json import string from pathlib import Path from random import sample from typing import Optional from traceback import format_exc from pydantic.main import BaseModel from nonebot.adapters.cqhttp import MessageEvent from nonebot.matcher import Matcher from nonebot.message import run_postprocessor from .log import logger ERROR_FILE = Path('.') / 'ATRI' / 'data' / 'errors' ERROR_FILE.parent.mkdir(exist_ok=True, parents=True) class ExceptionInfo(BaseModel): error_id: str prompt: str time: str error_content: str def store_error(error_id: str, prompt, error_content: str) -> None: data = ExceptionInfo( error_id=error_id, prompt=prompt, time=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), error_content=error_content ) path = ERROR_FILE / f"{error_id}.json" path.parent.mkdir(exist_ok=True, parents=True) with open(path, 'w', encoding='utf-8') as target: target.write( json.dumps( data.dict(), indent=4 ) ) def read_error(error_id: str) -> dict: path = ERROR_FILE / f"{error_id}.json" try: with open(path, 'r', encoding='utf-8') as target: data = target.read() return json.loads(data) except FileNotFoundError: raise FileNotFoundError class BaseBotException(BaseException): prompt: Optional[str] = 'ignore' def __init__(self, prompt: Optional[str]) -> None: super().__init__(self) self.prompt = prompt or self.__class__.prompt \ or self.__class__.__name__ self.error_content = format_exc() self.error_id = ''.join( sample(string.ascii_letters + string.digits, 16) ) class NotConfigured(BaseBotException): prompt = "缺少配置" class InvalidConfigured(BaseBotException): prompt = "无效配置" class WriteError(BaseBotException): prompt = "写入错误" class LoadingError(BaseBotException): prompt = "加载错误" class RequestTimeOut(BaseBotException): prompt = "网页/接口请求超时" @run_postprocessor # type: ignore async def _(matcher: Matcher, exception: Optional[Exception], event: MessageEvent, state: dict) -> None: """检测Bot运行中的报错,并进行提醒""" print(114514) if not exception: return try: raise exception except BaseBotException as Error: prompt = Error.prompt or Error.__class__.__name__ error_id = Error.error_id # error_content = format_exc() except Exception as Error: prompt = "Unknown ERROR" + Error.__class__.__name__ error_id = ''.join( sample(string.ascii_letters + string.digits, 16) ) store_error(error_id, prompt, format_exc()) logger.debug(f"A bug has been cumming, trace ID: {error_id}") msg = ( "[WARNING] 这是一个错误...\n" f"Track ID: {error_id}\n" f"Reason: {prompt}\n" "ごんめなさい... ;w;" ) await matcher.finish(msg)