Skip to content

Commit ac32935

Browse files
authored
Merge pull request #69 from MuRainBot/dev
合并Dev:重构QQRichText的cq和array格式的解析器,修改日志格式,添加Rule重载运算符的功能,修复一些bug
2 parents 4783571 + 940b356 commit ac32935

File tree

13 files changed

+516
-273
lines changed

13 files changed

+516
-273
lines changed

Lib/common.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import sys
77
import threading
88
import time
9-
import traceback
109
import uuid
1110
from collections import OrderedDict
1211
from io import BytesIO
@@ -222,14 +221,32 @@ def save_exc_dump(description: str = None, path: str = None):
222221
description: 保存的dump描述,为空则默认
223222
path: 保存的路径,为空则自动根据错误生成
224223
"""
224+
# 扫描是否存在非当前日期且为归档的exc_dump
225+
exc_dump_files = [
226+
file for file in os.listdir(DUMPS_PATH) if file.startswith("coredumpy_") and file.endswith(".dump")
227+
]
228+
229+
today_date = time.strftime("%Y%m%d")
230+
date_flags = []
231+
232+
for file in exc_dump_files:
233+
file_date = file.split("coredumpy_", 1)[1].split("_", 1)[0][:len("YYYYMMDD")]
234+
if file_date != today_date:
235+
os.makedirs(os.path.join(DUMPS_PATH, f"coredumpy_archive_{file_date}"), exist_ok=True)
236+
os.rename(os.path.join(DUMPS_PATH, file), os.path.join(DUMPS_PATH, f"coredumpy_archive_{file_date}", file))
237+
if file_date not in date_flags:
238+
logger.info(f"已自动归档 {file_date} 的异常堆栈到 coredumpy_archive_{file_date}")
239+
date_flags.append(file_date)
240+
241+
# 保存dump文件
225242
try:
226243
import coredumpy
227244
except ImportError:
228245
logger.warning("coredumpy未安装,无法保存异常堆栈")
229-
return
246+
return None
230247

231248
try:
232-
exc_type, exc_value, exc_traceback = sys.exc_info()
249+
_, _, exc_traceback = sys.exc_info()
233250
if not exc_traceback:
234251
raise Exception("No traceback found")
235252

@@ -245,12 +262,12 @@ def save_exc_dump(description: str = None, path: str = None):
245262
if i > 0:
246263
path_ = os.path.join(DUMPS_PATH,
247264
f"coredumpy_"
248-
f"{time.strftime('%Y%m%d%H%M%S')}_"
265+
f"{time.strftime('%Y%m%d%-H%M%S')}_"
249266
f"{frame.f_code.co_name}_{i}.dump")
250267
else:
251268
path_ = os.path.join(DUMPS_PATH,
252269
f"coredumpy_"
253-
f"{time.strftime('%Y%m%d%H%M%S')}_"
270+
f"{time.strftime('%Y%m%d-%H%M%S')}_"
254271
f"{frame.f_code.co_name}.dump")
255272
if not os.path.exists(path_):
256273
break
@@ -270,8 +287,7 @@ def save_exc_dump(description: str = None, path: str = None):
270287

271288
coredumpy.dump(**kwargs)
272289
except Exception as e:
273-
logger.error(f"保存异常堆栈时发生错误: {repr(e)}\n"
274-
f"{traceback.format_exc()}")
290+
logger.error(f"保存异常堆栈时发生错误: {repr(e)}", exc_info=True)
275291
return None
276292

277293
return kwargs["path"]

Lib/core/EventManager.py

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
"""
22
事件管理器,用于管理事件与事件监听器
33
"""
4-
import traceback
5-
from typing import Any, TypeVar
6-
4+
import inspect
75
from collections.abc import Callable
86
from dataclasses import dataclass, field
7+
from typing import Any, TypeVar
98

109
from Lib.core.ThreadPool import async_task
1110
from Lib.core import ConfigManager
1211
from Lib.utils import Logger
13-
import inspect
12+
from Lib.common import save_exc_dump
1413

1514
logger = Logger.get_logger()
1615

@@ -26,6 +25,7 @@ class Hook(_Event):
2625
"""
2726
钩子事件,用于在事件处理过程中跳过某些监听器
2827
"""
28+
2929
def __init__(self, event, listener):
3030
self.event = event
3131
self.listener = listener
@@ -36,17 +36,21 @@ def call(self):
3636
"""
3737
if self.__class__ in event_listeners:
3838
for listener in sorted(event_listeners[self.__class__], key=lambda i: i.priority, reverse=True):
39-
if not ConfigManager.GlobalConfig().debug.enable:
40-
try:
41-
res = listener.func(self, **listener.kwargs)
42-
except Exception as e:
43-
logger.error(f"Error occurred in listener: {repr(e)}\n{traceback.format_exc()}")
44-
continue
45-
else:
39+
try:
4640
res = listener.func(self, **listener.kwargs)
41+
except Exception as e:
42+
if ConfigManager.GlobalConfig().debug.save_dump:
43+
dump_path = save_exc_dump(f"监听器中发生错误")
44+
else:
45+
dump_path = None
46+
logger.error(f"监听器中发生错误: {repr(e)}"
47+
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
48+
exc_info=True)
49+
continue
4750
if res is True:
4851
return True
4952
return False
53+
return None
5054

5155

5256
T = TypeVar('T', bound='_Event')
@@ -64,7 +68,7 @@ class EventListener:
6468

6569
def __post_init__(self):
6670
# 确保监听器函数至少有一个参数
67-
assert len(inspect.signature(self.func).parameters) >= 1, "The listener takes at least 1 parameter"
71+
assert len(inspect.signature(self.func).parameters) >= 1, "监听器至少接受 1 个参数"
6872

6973

7074
# 定义监听器的类型和存储
@@ -81,7 +85,8 @@ def event_listener(event_class: type[T], priority: int = 0, **kwargs):
8185
priority: 优先级,默认为0
8286
**kwargs: 附加参数
8387
"""
84-
assert issubclass(event_class, _Event), "Event class must be a subclass of Event"
88+
if not issubclass(event_class, _Event):
89+
raise TypeError("event_class 类必须是 _Event 的子类")
8590

8691
def wrapper(func: Callable[[T, ...], Any]):
8792
# 注册事件监听器
@@ -92,6 +97,40 @@ def wrapper(func: Callable[[T, ...], Any]):
9297
return wrapper
9398

9499

100+
def unregister_listener(event_class: type[T], func: Callable[[T, ...], Any]):
101+
"""
102+
用于取消注册监听器
103+
注意,会删除所有与给定函数匹配的监听器。
104+
105+
Args:
106+
event_class: 事件类型
107+
func: 监听器函数
108+
"""
109+
if not issubclass(event_class, _Event):
110+
raise TypeError("event_class 类必须是 _Event 的子类")
111+
112+
listeners_list = event_listeners.get(event_class)
113+
114+
if not listeners_list:
115+
raise ValueError(f"事件类型 {event_class.__name__} 没有已注册的监听器。")
116+
117+
# 查找所有与给定函数匹配的监听器对象
118+
listeners_to_remove = [listener for listener in listeners_list if listener.func == func]
119+
120+
if not listeners_to_remove:
121+
# 如果没有找到匹配的函数
122+
raise ValueError(f"未找到函数 {func.__name__} 对应的监听器,无法为事件 {event_class.__name__} 注销。")
123+
124+
# 移除所有找到的监听器
125+
removed_count = 0
126+
for listener_obj in listeners_to_remove:
127+
listeners_list.remove(listener_obj)
128+
removed_count += 1
129+
130+
if not listeners_list:
131+
del event_listeners[event_class]
132+
133+
95134
class Event(_Event):
96135
"""
97136
基事件类,所有自定义事件均继承自此类,继承自此类以创建自定义事件
@@ -108,16 +147,19 @@ def call(self):
108147
res_list = []
109148
for listener in sorted(event_listeners[self.__class__], key=lambda i: i.priority, reverse=True):
110149
if self._call_hook(listener):
111-
logger.debug(f"Skipped listener: {listener.func.__name__}")
150+
logger.debug(f"由 Hook 跳过监听器: {listener.func.__name__}")
112151
continue
113-
if not ConfigManager.GlobalConfig().debug.enable:
114-
try:
115-
res = listener.func(self, **listener.kwargs)
116-
except Exception as e:
117-
logger.error(f"Error occurred in listener: {repr(e)}\n{traceback.format_exc()}")
118-
continue
119-
else:
152+
try:
120153
res = listener.func(self, **listener.kwargs)
154+
except Exception as e:
155+
if ConfigManager.GlobalConfig().debug.save_dump:
156+
dump_path = save_exc_dump(f"监听器中发生错误")
157+
else:
158+
dump_path = None
159+
logger.error(f"监听器中发生错误: {repr(e)}"
160+
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
161+
exc_info=True)
162+
continue
121163
res_list.append(res)
122164

123165
@async_task

Lib/core/OnebotAPI.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,9 @@ def get(self, node, data: dict = None, original: bool = None):
128128
else:
129129
dump_path = None
130130
logger.error(
131-
f"调用 API: {node} data: {data} 异常: {repr(e)}\n"
132-
f"{traceback.format_exc()}"
133-
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}"
131+
f"调用 API: {node} data: {data} 异常: {repr(e)}"
132+
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
133+
exc_info=True
134134
)
135135
raise e
136136

Lib/core/PluginManager.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import importlib
77
import inspect
88
import sys
9-
import traceback
109

1110
from Lib.common import save_exc_dump
1211
from Lib.constants import *
@@ -61,8 +60,7 @@ def load_plugin(plugin):
6160
logger.debug(f"尝试加载: {import_path}")
6261
module = importlib.import_module(import_path)
6362
except ImportError as e:
64-
logger.error(f"加载 {import_path} 失败: {repr(e)}\n"
65-
f"{traceback.format_exc()}")
63+
logger.error(f"加载 {import_path} 失败: {repr(e)}", exc_info=True)
6664
raise
6765

6866
plugin_info = None
@@ -133,9 +131,9 @@ def load_plugins():
133131
dump_path = save_exc_dump(f"尝试加载插件 {full_path} 时失败")
134132
else:
135133
dump_path = None
136-
logger.error(f"尝试加载插件 {full_path} 时失败! 原因:{repr(e)}\n"
137-
f"{"".join(traceback.format_exc())}"
138-
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}")
134+
logger.error(f"尝试加载插件 {full_path} 时失败! 原因:{repr(e)}"
135+
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
136+
exc_info=True)
139137
continue
140138

141139
logger.debug(f"插件 {name}({full_path}) 加载成功!")
@@ -188,9 +186,9 @@ def requirement_plugin(plugin_name: str):
188186
dump_path = save_exc_dump(f"尝试加载被依赖的插件 {plugin_name} 时失败!")
189187
else:
190188
dump_path = None
191-
logger.error(f"尝试加载被依赖的插件 {plugin_name} 时失败! 原因:{repr(e)}\n"
192-
f"{"".join(traceback.format_exc())}"
193-
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}")
189+
logger.error(f"尝试加载被依赖的插件 {plugin_name} 时失败! 原因:{repr(e)}"
190+
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
191+
exc_info=True)
194192
raise e
195193
logger.debug(f"由于插件依赖,插件 {plugin_name} 加载成功!")
196194
else:

Lib/core/ThreadPool.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@
33
Created by BigCookie233
44
"""
55

6-
import sys
7-
import traceback
6+
import atexit
87
from concurrent.futures import ThreadPoolExecutor
98

9+
from Lib.common import save_exc_dump
1010
from Lib.core import ConfigManager
1111
from Lib.core.ConfigManager import GlobalConfig
1212
from Lib.utils.Logger import get_logger
13-
from Lib.common import save_exc_dump
14-
15-
import atexit
1613

1714
thread_pool = None
1815
logger = get_logger()
@@ -50,10 +47,11 @@ def _wrapper(func, *args, **kwargs):
5047
dump_path = None
5148
# 打印到日志中
5249
logger.error(
53-
f"Error in async task({func.__module__}.{func.__name__}): {repr(e)}\n"
54-
f"{"".join(traceback.format_exc())}"
55-
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}"
50+
f"Error in async task({func.__module__}.{func.__name__}): {repr(e)}"
51+
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
52+
exc_info=True
5653
)
54+
return None
5755

5856

5957
def async_task(func):

Lib/utils/Actions.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
操作
33
"""
44

5-
import traceback
6-
75
from Lib.common import save_exc_dump
86
from Lib.core import OnebotAPI, ThreadPool, ConfigManager
97
from Lib.utils import QQRichText, Logger, QQDataCacher
@@ -110,8 +108,8 @@ def set_callback(self, callback: Callable[[Result], ...]):
110108
else:
111109
dump_path = None
112110
logger.warning(f"执行回调函数异常: {repr(e)}\n"
113-
f"{traceback.format_exc()}"
114-
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}")
111+
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
112+
exc_info=True)
115113
return self
116114

117115
def call(self):
@@ -133,9 +131,9 @@ def call(self):
133131
dump_path = save_exc_dump(f"调用日志记录函数异常")
134132
else:
135133
dump_path = None
136-
logger.warning(f"调用日志记录函数异常: {repr(e)}\n"
137-
f"{traceback.format_exc()}"
138-
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}")
134+
logger.warning(f"调用日志记录函数异常: {repr(e)}"
135+
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
136+
exc_info=True)
139137
if self.callback is not None:
140138
try:
141139
self.callback(self._result)
@@ -144,9 +142,9 @@ def call(self):
144142
dump_path = save_exc_dump(f"执行回调函数异常")
145143
else:
146144
dump_path = None
147-
logger.warning(f"回调函数异常: {repr(e)}\n"
148-
f"{traceback.format_exc()}"
149-
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}")
145+
logger.warning(f"回调函数异常: {repr(e)}"
146+
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
147+
exc_info=True)
150148
return self
151149

152150
def logger(self, *args, **kwargs):

Lib/utils/EventClassifier.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ def logger(self):
166166
f"{self.message.render()}"
167167
f"({self.message_id})"
168168
)
169+
return None
169170

170171
elif self.sub_type == "group":
171172
logger.info(
@@ -182,6 +183,7 @@ def logger(self):
182183
f"{self.message.render()}"
183184
f"({self.message_id})"
184185
)
186+
return None
185187

186188
elif self.sub_type == "other":
187189
logger.info(
@@ -195,6 +197,7 @@ def logger(self):
195197
f"{self.message.render()}"
196198
f"({self.message_id})"
197199
)
200+
return None
198201

199202
else:
200203
return super().logger()
@@ -227,6 +230,7 @@ def logger(self):
227230
f"{self.message.render(group_id=self.group_id)}"
228231
f"({self.message_id})"
229232
)
233+
return None
230234

231235
elif self.sub_type == "anonymous":
232236
anonymous_data = self.get('anonymous', {})
@@ -242,6 +246,7 @@ def logger(self):
242246
f"{self.message.render(group_id=self.group_id)}"
243247
f"({self.message_id})"
244248
)
249+
return None
245250

246251
elif self.sub_type == "notice":
247252
logger.info(
@@ -252,6 +257,7 @@ def logger(self):
252257
f"{self.message.render(group_id=self.group_id)}"
253258
f"({self.message_id})"
254259
)
260+
return None
255261

256262
else:
257263
return super().logger()

0 commit comments

Comments
 (0)