ErisPulse 2.1.13rc2__py3-none-any.whl → 2.1.14a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ErisPulse/Core/__init__.py +8 -6
- ErisPulse/Core/adapter.py +18 -15
- ErisPulse/Core/config.py +0 -98
- ErisPulse/Core/env.py +1 -32
- ErisPulse/Core/erispulse_config.py +105 -0
- ErisPulse/Core/exceptions.py +108 -0
- ErisPulse/Core/logger.py +74 -1
- ErisPulse/Core/{server.py → router.py} +51 -70
- ErisPulse/__init__.py +21 -9
- ErisPulse/__main__.py +70 -23
- {erispulse-2.1.13rc2.dist-info → erispulse-2.1.14a1.dist-info}/METADATA +1 -1
- erispulse-2.1.14a1.dist-info/RECORD +16 -0
- ErisPulse/Core/raiserr.py +0 -181
- ErisPulse/Core/util.py +0 -123
- erispulse-2.1.13rc2.dist-info/RECORD +0 -16
- {erispulse-2.1.13rc2.dist-info → erispulse-2.1.14a1.dist-info}/WHEEL +0 -0
- {erispulse-2.1.13rc2.dist-info → erispulse-2.1.14a1.dist-info}/entry_points.txt +0 -0
- {erispulse-2.1.13rc2.dist-info → erispulse-2.1.14a1.dist-info}/licenses/LICENSE +0 -0
ErisPulse/Core/__init__.py
CHANGED
|
@@ -2,9 +2,10 @@ from .adapter import AdapterFather, SendDSL, adapter
|
|
|
2
2
|
from .env import env
|
|
3
3
|
from .logger import logger
|
|
4
4
|
from .mods import mods
|
|
5
|
-
from .
|
|
6
|
-
from .
|
|
7
|
-
from .
|
|
5
|
+
from .router import router, adapter_server
|
|
6
|
+
from .config import config
|
|
7
|
+
from . import exceptions
|
|
8
|
+
|
|
8
9
|
BaseAdapter = AdapterFather
|
|
9
10
|
|
|
10
11
|
__all__ = [
|
|
@@ -15,7 +16,8 @@ __all__ = [
|
|
|
15
16
|
'env',
|
|
16
17
|
'logger',
|
|
17
18
|
'mods',
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'adapter_server'
|
|
19
|
+
'exceptions',
|
|
20
|
+
'router',
|
|
21
|
+
'adapter_server',
|
|
22
|
+
'config'
|
|
21
23
|
]
|
ErisPulse/Core/adapter.py
CHANGED
|
@@ -13,14 +13,12 @@ ErisPulse 适配器系统
|
|
|
13
13
|
|
|
14
14
|
import functools
|
|
15
15
|
import asyncio
|
|
16
|
-
import uuid
|
|
17
|
-
import time
|
|
18
16
|
from typing import (
|
|
19
17
|
Callable, Any, Dict, List, Type, Optional, Set,
|
|
20
|
-
Union, Awaitable
|
|
18
|
+
Union, Awaitable
|
|
21
19
|
)
|
|
22
20
|
from collections import defaultdict
|
|
23
|
-
|
|
21
|
+
from .logger import logger
|
|
24
22
|
|
|
25
23
|
class SendDSLBase:
|
|
26
24
|
"""
|
|
@@ -114,7 +112,6 @@ class BaseAdapter:
|
|
|
114
112
|
:example:
|
|
115
113
|
>>> await adapter.Send.To("123").Example("Hello")
|
|
116
114
|
"""
|
|
117
|
-
from .logger import logger
|
|
118
115
|
logger.debug(f"适配器 {self._adapter.__class__.__name__} 发送了实例类型的消息: {text}")
|
|
119
116
|
|
|
120
117
|
|
|
@@ -378,7 +375,7 @@ class AdapterManager:
|
|
|
378
375
|
for name in set(combinations):
|
|
379
376
|
setattr(self, name, instance)
|
|
380
377
|
else:
|
|
381
|
-
|
|
378
|
+
logger.warning(f"平台名 {platform} 过长,如果您是开发者,请考虑使用更短的名称")
|
|
382
379
|
setattr(self, platform.lower(), instance)
|
|
383
380
|
setattr(self, platform.upper(), instance)
|
|
384
381
|
setattr(self, platform.capitalize(), instance)
|
|
@@ -401,10 +398,18 @@ class AdapterManager:
|
|
|
401
398
|
"""
|
|
402
399
|
if platforms is None:
|
|
403
400
|
platforms = list(self._adapters.keys())
|
|
401
|
+
if not isinstance(platforms, list):
|
|
402
|
+
platforms = [platforms]
|
|
403
|
+
for platform in platforms:
|
|
404
|
+
if platform not in self._adapters:
|
|
405
|
+
raise ValueError(f"平台 {platform} 未注册")
|
|
406
|
+
|
|
407
|
+
logger.info(f"启动适配器 {platforms}")
|
|
404
408
|
|
|
405
|
-
from .
|
|
406
|
-
from .
|
|
409
|
+
from .router import adapter_server
|
|
410
|
+
from .erispulse_config import get_server_config
|
|
407
411
|
server_config = get_server_config()
|
|
412
|
+
|
|
408
413
|
host = server_config["host"]
|
|
409
414
|
port = server_config["port"]
|
|
410
415
|
ssl_cert = server_config.get("ssl_certfile", None)
|
|
@@ -441,16 +446,14 @@ class AdapterManager:
|
|
|
441
446
|
:param adapter: 适配器实例
|
|
442
447
|
:param platform: 平台名称
|
|
443
448
|
"""
|
|
444
|
-
from .. import sdk
|
|
445
449
|
|
|
446
|
-
# 加锁防止并发启动
|
|
447
450
|
if not getattr(adapter, "_starting_lock", None):
|
|
448
451
|
adapter._starting_lock = asyncio.Lock()
|
|
449
452
|
|
|
450
453
|
async with adapter._starting_lock:
|
|
451
454
|
# 再次确认是否已经被启动
|
|
452
455
|
if adapter in self._started_instances:
|
|
453
|
-
|
|
456
|
+
logger.info(f"适配器 {platform}(实例ID: {id(adapter)})已被其他协程启动,跳过")
|
|
454
457
|
return
|
|
455
458
|
|
|
456
459
|
retry_count = 0
|
|
@@ -464,12 +467,12 @@ class AdapterManager:
|
|
|
464
467
|
return
|
|
465
468
|
except Exception as e:
|
|
466
469
|
retry_count += 1
|
|
467
|
-
|
|
470
|
+
logger.error(f"平台 {platform} 启动失败(第{retry_count}次重试): {e}")
|
|
468
471
|
|
|
469
472
|
try:
|
|
470
473
|
await adapter.shutdown()
|
|
471
474
|
except Exception as stop_err:
|
|
472
|
-
|
|
475
|
+
logger.warning(f"停止适配器失败: {stop_err}")
|
|
473
476
|
|
|
474
477
|
# 计算等待时间
|
|
475
478
|
if retry_count <= len(backoff_intervals):
|
|
@@ -477,7 +480,7 @@ class AdapterManager:
|
|
|
477
480
|
else:
|
|
478
481
|
wait_time = fixed_delay
|
|
479
482
|
|
|
480
|
-
|
|
483
|
+
logger.info(f"将在 {wait_time // 60} 分钟后再次尝试重启 {platform}")
|
|
481
484
|
await asyncio.sleep(wait_time)
|
|
482
485
|
|
|
483
486
|
async def shutdown(self) -> None:
|
|
@@ -490,7 +493,7 @@ class AdapterManager:
|
|
|
490
493
|
for adapter in self._adapters.values():
|
|
491
494
|
await adapter.shutdown()
|
|
492
495
|
|
|
493
|
-
from .
|
|
496
|
+
from .router import adapter_server
|
|
494
497
|
await adapter_server.stop()
|
|
495
498
|
|
|
496
499
|
def get(self, platform: str) -> Optional[BaseAdapter]:
|
ErisPulse/Core/config.py
CHANGED
|
@@ -72,101 +72,3 @@ class ConfigManager:
|
|
|
72
72
|
return False
|
|
73
73
|
|
|
74
74
|
config = ConfigManager()
|
|
75
|
-
|
|
76
|
-
# 默认配置
|
|
77
|
-
DEFAULT_CONFIG = {
|
|
78
|
-
"server": {
|
|
79
|
-
"host": "0.0.0.0",
|
|
80
|
-
"port": 8000,
|
|
81
|
-
"ssl_certfile": None,
|
|
82
|
-
"ssl_keyfile": None
|
|
83
|
-
},
|
|
84
|
-
"logger": {
|
|
85
|
-
"level": "INFO",
|
|
86
|
-
"log_files": [],
|
|
87
|
-
"memory_limit": 1000
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
def _ensure_config_structure(config: Dict[str, Any]) -> Dict[str, Any]:
|
|
92
|
-
"""
|
|
93
|
-
确保配置结构完整,补全缺失的配置项
|
|
94
|
-
|
|
95
|
-
:param config: 当前配置
|
|
96
|
-
:return: 补全后的完整配置
|
|
97
|
-
"""
|
|
98
|
-
merged_config = DEFAULT_CONFIG.copy()
|
|
99
|
-
|
|
100
|
-
# 深度合并配置
|
|
101
|
-
for section, default_values in DEFAULT_CONFIG.items():
|
|
102
|
-
if section not in config:
|
|
103
|
-
config[section] = default_values.copy()
|
|
104
|
-
continue
|
|
105
|
-
|
|
106
|
-
if not isinstance(config[section], dict):
|
|
107
|
-
config[section] = default_values.copy()
|
|
108
|
-
continue
|
|
109
|
-
|
|
110
|
-
for key, default_value in default_values.items():
|
|
111
|
-
if key not in config[section]:
|
|
112
|
-
config[section][key] = default_value
|
|
113
|
-
|
|
114
|
-
return config
|
|
115
|
-
|
|
116
|
-
def get_config() -> Dict[str, Any]:
|
|
117
|
-
"""
|
|
118
|
-
获取当前配置,自动补全缺失的配置项并保存
|
|
119
|
-
|
|
120
|
-
:return: 完整的配置字典
|
|
121
|
-
"""
|
|
122
|
-
|
|
123
|
-
# 获取现有配置
|
|
124
|
-
current_config = config.getConfig("ErisPulse")
|
|
125
|
-
|
|
126
|
-
# 如果完全没有配置,设置默认配置
|
|
127
|
-
if current_config is None:
|
|
128
|
-
config.setConfig("ErisPulse", DEFAULT_CONFIG)
|
|
129
|
-
return DEFAULT_CONFIG
|
|
130
|
-
|
|
131
|
-
# 检查并补全缺失的配置项
|
|
132
|
-
complete_config = _ensure_config_structure(current_config)
|
|
133
|
-
|
|
134
|
-
# 如果配置有变化,更新到存储
|
|
135
|
-
if current_config != complete_config:
|
|
136
|
-
config.setConfig("ErisPulse", complete_config)
|
|
137
|
-
|
|
138
|
-
return complete_config
|
|
139
|
-
|
|
140
|
-
def update_config(new_config: Dict[str, Any]) -> bool:
|
|
141
|
-
"""
|
|
142
|
-
更新配置,自动补全缺失的配置项
|
|
143
|
-
|
|
144
|
-
:param new_config: 新的配置字典
|
|
145
|
-
:return: 是否更新成功
|
|
146
|
-
"""
|
|
147
|
-
# 获取当前配置并合并新配置
|
|
148
|
-
current = get_config()
|
|
149
|
-
merged = {**current, **new_config}
|
|
150
|
-
|
|
151
|
-
# 确保合并后的配置结构完整
|
|
152
|
-
complete_config = _ensure_config_structure(merged)
|
|
153
|
-
|
|
154
|
-
return config.setConfig("ErisPulse", complete_config)
|
|
155
|
-
|
|
156
|
-
def get_server_config() -> Dict[str, Any]:
|
|
157
|
-
"""
|
|
158
|
-
获取服务器配置,确保结构完整
|
|
159
|
-
|
|
160
|
-
:return: 服务器配置字典
|
|
161
|
-
"""
|
|
162
|
-
config = get_config()
|
|
163
|
-
return config["server"]
|
|
164
|
-
|
|
165
|
-
def get_logger_config() -> Dict[str, Any]:
|
|
166
|
-
"""
|
|
167
|
-
获取日志配置,确保结构完整
|
|
168
|
-
|
|
169
|
-
:return: 日志配置字典
|
|
170
|
-
"""
|
|
171
|
-
config = get_config()
|
|
172
|
-
return config["logger"]
|
ErisPulse/Core/env.py
CHANGED
|
@@ -13,14 +13,10 @@ ErisPulse 环境配置模块
|
|
|
13
13
|
import os
|
|
14
14
|
import json
|
|
15
15
|
import sqlite3
|
|
16
|
-
import importlib.util
|
|
17
16
|
import shutil
|
|
18
17
|
import time
|
|
19
|
-
import toml
|
|
20
|
-
from pathlib import Path
|
|
21
18
|
from datetime import datetime
|
|
22
|
-
from
|
|
23
|
-
from typing import List, Dict, Optional, Any, Set, Tuple, Union, Type, FrozenSet
|
|
19
|
+
from typing import List, Dict, Optional, Any, Tuple, Type
|
|
24
20
|
|
|
25
21
|
class EnvManager:
|
|
26
22
|
"""
|
|
@@ -39,7 +35,6 @@ class EnvManager:
|
|
|
39
35
|
db_path = os.path.join(os.path.dirname(__file__), "../data/config.db")
|
|
40
36
|
SNAPSHOT_DIR = os.path.join(os.path.dirname(__file__), "../data/snapshots")
|
|
41
37
|
|
|
42
|
-
CONFIG_FILE = "config.toml"
|
|
43
38
|
|
|
44
39
|
def __new__(cls, *args, **kwargs):
|
|
45
40
|
if not cls._instance:
|
|
@@ -192,8 +187,6 @@ class EnvManager:
|
|
|
192
187
|
from .config import config
|
|
193
188
|
return config.getConfig(key, default)
|
|
194
189
|
except Exception as e:
|
|
195
|
-
from . import logger
|
|
196
|
-
logger.error(f"读取配置文件 {self.CONFIG_FILE} 失败: {e}")
|
|
197
190
|
return default
|
|
198
191
|
|
|
199
192
|
def setConfig(self, key: str, value: Any) -> bool:
|
|
@@ -207,8 +200,6 @@ class EnvManager:
|
|
|
207
200
|
from .config import config
|
|
208
201
|
return config.setConfig(key, value)
|
|
209
202
|
except Exception as e:
|
|
210
|
-
from . import logger
|
|
211
|
-
logger.error(f"写入配置文件 {self.CONFIG_FILE} 失败: {e}")
|
|
212
203
|
return False
|
|
213
204
|
|
|
214
205
|
def delete(self, key: str) -> bool:
|
|
@@ -385,29 +376,7 @@ class EnvManager:
|
|
|
385
376
|
return True
|
|
386
377
|
except Exception as e:
|
|
387
378
|
return False
|
|
388
|
-
|
|
389
|
-
def load_env_file(self) -> bool:
|
|
390
|
-
"""
|
|
391
|
-
加载env.py文件中的配置项
|
|
392
379
|
|
|
393
|
-
:return: 操作是否成功
|
|
394
|
-
|
|
395
|
-
:example:
|
|
396
|
-
>>> env.load_env_file() # 加载env.py中的配置
|
|
397
|
-
"""
|
|
398
|
-
try:
|
|
399
|
-
env_file = Path("env.py")
|
|
400
|
-
if env_file.exists():
|
|
401
|
-
spec = importlib.util.spec_from_file_location("env_module", env_file)
|
|
402
|
-
env_module = importlib.util.module_from_spec(spec)
|
|
403
|
-
spec.loader.exec_module(env_module)
|
|
404
|
-
for key, value in vars(env_module).items():
|
|
405
|
-
if not key.startswith("__") and isinstance(value, (dict, list, str, int, float, bool)):
|
|
406
|
-
self.set(key, value)
|
|
407
|
-
return True
|
|
408
|
-
except Exception as e:
|
|
409
|
-
return False
|
|
410
|
-
|
|
411
380
|
def __getattr__(self, key: str) -> Any:
|
|
412
381
|
"""
|
|
413
382
|
通过属性访问配置项
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ErisPulse 框架配置管理
|
|
3
|
+
|
|
4
|
+
专门管理 ErisPulse 框架自身的配置项。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, Any
|
|
8
|
+
from .config import config
|
|
9
|
+
|
|
10
|
+
# 默认配置
|
|
11
|
+
DEFAULT_ERISPULSE_CONFIG = {
|
|
12
|
+
"server": {
|
|
13
|
+
"host": "0.0.0.0",
|
|
14
|
+
"port": 8000,
|
|
15
|
+
"ssl_certfile": None,
|
|
16
|
+
"ssl_keyfile": None
|
|
17
|
+
},
|
|
18
|
+
"logger": {
|
|
19
|
+
"level": "INFO",
|
|
20
|
+
"log_files": [],
|
|
21
|
+
"memory_limit": 1000
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
def _ensure_erispulse_config_structure(config_dict: Dict[str, Any]) -> Dict[str, Any]:
|
|
26
|
+
"""
|
|
27
|
+
确保 ErisPulse 配置结构完整,补全缺失的配置项
|
|
28
|
+
|
|
29
|
+
:param config_dict: 当前配置
|
|
30
|
+
:return: 补全后的完整配置
|
|
31
|
+
"""
|
|
32
|
+
merged_config = DEFAULT_ERISPULSE_CONFIG.copy()
|
|
33
|
+
|
|
34
|
+
# 深度合并配置
|
|
35
|
+
for section, default_values in DEFAULT_ERISPULSE_CONFIG.items():
|
|
36
|
+
if section not in config_dict:
|
|
37
|
+
config_dict[section] = default_values.copy()
|
|
38
|
+
continue
|
|
39
|
+
|
|
40
|
+
if not isinstance(config_dict[section], dict):
|
|
41
|
+
config_dict[section] = default_values.copy()
|
|
42
|
+
continue
|
|
43
|
+
|
|
44
|
+
for key, default_value in default_values.items():
|
|
45
|
+
if key not in config_dict[section]:
|
|
46
|
+
config_dict[section][key] = default_value
|
|
47
|
+
|
|
48
|
+
return config_dict
|
|
49
|
+
|
|
50
|
+
def get_erispulse_config() -> Dict[str, Any]:
|
|
51
|
+
"""
|
|
52
|
+
获取 ErisPulse 框架配置,自动补全缺失的配置项并保存
|
|
53
|
+
|
|
54
|
+
:return: 完整的 ErisPulse 配置字典
|
|
55
|
+
"""
|
|
56
|
+
# 获取现有配置
|
|
57
|
+
current_config = config.getConfig("ErisPulse")
|
|
58
|
+
|
|
59
|
+
# 如果完全没有配置,设置默认配置
|
|
60
|
+
if current_config is None:
|
|
61
|
+
config.setConfig("ErisPulse", DEFAULT_ERISPULSE_CONFIG)
|
|
62
|
+
return DEFAULT_ERISPULSE_CONFIG
|
|
63
|
+
|
|
64
|
+
# 检查并补全缺失的配置项
|
|
65
|
+
complete_config = _ensure_erispulse_config_structure(current_config)
|
|
66
|
+
|
|
67
|
+
# 如果配置有变化,更新到存储
|
|
68
|
+
if current_config != complete_config:
|
|
69
|
+
config.setConfig("ErisPulse", complete_config)
|
|
70
|
+
|
|
71
|
+
return complete_config
|
|
72
|
+
|
|
73
|
+
def update_erispulse_config(new_config: Dict[str, Any]) -> bool:
|
|
74
|
+
"""
|
|
75
|
+
更新 ErisPulse 配置,自动补全缺失的配置项
|
|
76
|
+
|
|
77
|
+
:param new_config: 新的配置字典
|
|
78
|
+
:return: 是否更新成功
|
|
79
|
+
"""
|
|
80
|
+
# 获取当前配置并合并新配置
|
|
81
|
+
current = get_erispulse_config()
|
|
82
|
+
merged = {**current, **new_config}
|
|
83
|
+
|
|
84
|
+
# 确保合并后的配置结构完整
|
|
85
|
+
complete_config = _ensure_erispulse_config_structure(merged)
|
|
86
|
+
|
|
87
|
+
return config.setConfig("ErisPulse", complete_config)
|
|
88
|
+
|
|
89
|
+
def get_server_config() -> Dict[str, Any]:
|
|
90
|
+
"""
|
|
91
|
+
获取服务器配置,确保结构完整
|
|
92
|
+
|
|
93
|
+
:return: 服务器配置字典
|
|
94
|
+
"""
|
|
95
|
+
erispulse_config = get_erispulse_config()
|
|
96
|
+
return erispulse_config["server"]
|
|
97
|
+
|
|
98
|
+
def get_logger_config() -> Dict[str, Any]:
|
|
99
|
+
"""
|
|
100
|
+
获取日志配置,确保结构完整
|
|
101
|
+
|
|
102
|
+
:return: 日志配置字典
|
|
103
|
+
"""
|
|
104
|
+
erispulse_config = get_erispulse_config()
|
|
105
|
+
return erispulse_config["logger"]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ErisPulse 全局异常处理系统
|
|
3
|
+
|
|
4
|
+
提供统一的异常捕获和格式化功能,支持同步和异步代码的异常处理。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import traceback
|
|
9
|
+
import asyncio
|
|
10
|
+
import os
|
|
11
|
+
from typing import Dict, Any, Type
|
|
12
|
+
|
|
13
|
+
class ExceptionHandler:
|
|
14
|
+
@staticmethod
|
|
15
|
+
def format_exception(exc_type: Type[Exception], exc_value: Exception, exc_traceback: Any) -> str:
|
|
16
|
+
"""
|
|
17
|
+
:param exc_type: 异常类型
|
|
18
|
+
:param exc_value: 异常值
|
|
19
|
+
:param exc_traceback: 追踪信息
|
|
20
|
+
:return: 格式化后的异常信息
|
|
21
|
+
"""
|
|
22
|
+
tb_list = traceback.extract_tb(exc_traceback)
|
|
23
|
+
if tb_list:
|
|
24
|
+
last_frame = tb_list[-1]
|
|
25
|
+
filename = os.path.basename(last_frame.filename)
|
|
26
|
+
line_number = last_frame.lineno
|
|
27
|
+
function_name = last_frame.name
|
|
28
|
+
return f"ERROR: {filename}:{function_name}:{line_number}: {exc_type.__name__}: {exc_value}"
|
|
29
|
+
else:
|
|
30
|
+
return f"ERROR: {exc_type.__name__}: {exc_value}"
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def format_async_exception(exception: Exception) -> str:
|
|
34
|
+
"""
|
|
35
|
+
:param exception: 异常对象
|
|
36
|
+
:return: 格式化后的异常信息
|
|
37
|
+
"""
|
|
38
|
+
if exception.__traceback__:
|
|
39
|
+
tb_list = traceback.extract_tb(exception.__traceback__)
|
|
40
|
+
if tb_list:
|
|
41
|
+
last_frame = tb_list[-1]
|
|
42
|
+
filename = os.path.basename(last_frame.filename)
|
|
43
|
+
line_number = last_frame.lineno
|
|
44
|
+
function_name = last_frame.name
|
|
45
|
+
return f"ERROR: {filename}:{function_name}:{line_number}: {type(exception).__name__}: {exception}"
|
|
46
|
+
|
|
47
|
+
return f"ERROR: {type(exception).__name__}: {exception}"
|
|
48
|
+
|
|
49
|
+
def global_exception_handler(exc_type: Type[Exception], exc_value: Exception, exc_traceback: Any) -> None:
|
|
50
|
+
"""
|
|
51
|
+
全局异常处理器
|
|
52
|
+
|
|
53
|
+
:param exc_type: 异常类型
|
|
54
|
+
:param exc_value: 异常值
|
|
55
|
+
:param exc_traceback: 追踪信息
|
|
56
|
+
"""
|
|
57
|
+
try:
|
|
58
|
+
from ErisPulse import logger
|
|
59
|
+
err_logger = logger.error
|
|
60
|
+
except ImportError:
|
|
61
|
+
err_logger = sys.stderr.write
|
|
62
|
+
|
|
63
|
+
formatted_error = ExceptionHandler.format_exception(exc_type, exc_value, exc_traceback)
|
|
64
|
+
err_logger(formatted_error)
|
|
65
|
+
|
|
66
|
+
def async_exception_handler(loop: asyncio.AbstractEventLoop, context: Dict[str, Any]) -> None:
|
|
67
|
+
"""
|
|
68
|
+
异步异常处理器
|
|
69
|
+
|
|
70
|
+
:param loop: 事件循环
|
|
71
|
+
:param context: 上下文字典
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
from ErisPulse import logger
|
|
75
|
+
err_logger = logger.error
|
|
76
|
+
except ImportError:
|
|
77
|
+
err_logger = sys.stderr.write
|
|
78
|
+
|
|
79
|
+
exception = context.get('exception')
|
|
80
|
+
if exception:
|
|
81
|
+
try:
|
|
82
|
+
formatted_error = ExceptionHandler.format_async_exception(exception)
|
|
83
|
+
err_logger(formatted_error + '\n')
|
|
84
|
+
except Exception:
|
|
85
|
+
err_logger(f"ERROR: 捕捉器发生错误,原始异常信息:\n\n{exception}\n\n" + traceback.format_exc())
|
|
86
|
+
else:
|
|
87
|
+
msg = context.get('message', '未知异步错误')
|
|
88
|
+
err_logger(f"ERROR: 未处理的异步错误: {msg}\n")
|
|
89
|
+
|
|
90
|
+
def setup_async_loop(loop: asyncio.AbstractEventLoop = None) -> None:
|
|
91
|
+
"""
|
|
92
|
+
为指定的事件循环设置异常处理器
|
|
93
|
+
|
|
94
|
+
:param loop: 事件循环实例,如果为None则使用当前事件循环
|
|
95
|
+
"""
|
|
96
|
+
if loop is None:
|
|
97
|
+
try:
|
|
98
|
+
loop = asyncio.get_running_loop()
|
|
99
|
+
except RuntimeError:
|
|
100
|
+
loop = asyncio.get_event_loop()
|
|
101
|
+
|
|
102
|
+
loop.set_exception_handler(async_exception_handler)
|
|
103
|
+
|
|
104
|
+
sys.excepthook = global_exception_handler
|
|
105
|
+
try:
|
|
106
|
+
asyncio.get_event_loop().set_exception_handler(async_exception_handler)
|
|
107
|
+
except RuntimeError:
|
|
108
|
+
pass
|
ErisPulse/Core/logger.py
CHANGED
|
@@ -56,6 +56,10 @@ class Logger:
|
|
|
56
56
|
"""
|
|
57
57
|
if limit > 0:
|
|
58
58
|
self._max_logs = limit
|
|
59
|
+
# 更新所有已存在的日志列表大小
|
|
60
|
+
for module_name in self._logs:
|
|
61
|
+
while len(self._logs[module_name]) > self._max_logs:
|
|
62
|
+
self._logs[module_name].pop(0)
|
|
59
63
|
return True
|
|
60
64
|
else:
|
|
61
65
|
self._logger.warning("日志存储上限必须大于0。")
|
|
@@ -174,7 +178,7 @@ class Logger:
|
|
|
174
178
|
self._logs[ModuleName].append(msg)
|
|
175
179
|
|
|
176
180
|
def _setup_config(self):
|
|
177
|
-
from .
|
|
181
|
+
from .erispulse_config import get_logger_config
|
|
178
182
|
logger_config = get_logger_config()
|
|
179
183
|
if "level" in logger_config:
|
|
180
184
|
self.set_level(logger_config["level"])
|
|
@@ -198,6 +202,20 @@ class Logger:
|
|
|
198
202
|
module_name = "ErisPulse"
|
|
199
203
|
return module_name
|
|
200
204
|
|
|
205
|
+
def get_child(self, child_name: str = None):
|
|
206
|
+
"""
|
|
207
|
+
获取子日志记录器
|
|
208
|
+
|
|
209
|
+
:param child_name: 子模块名称(可选)
|
|
210
|
+
:return: LoggerChild 子日志记录器实例
|
|
211
|
+
"""
|
|
212
|
+
caller_module = self._get_caller()
|
|
213
|
+
if child_name:
|
|
214
|
+
full_module_name = f"{caller_module}.{child_name}"
|
|
215
|
+
else:
|
|
216
|
+
full_module_name = caller_module
|
|
217
|
+
return LoggerChild(self, full_module_name)
|
|
218
|
+
|
|
201
219
|
def debug(self, msg, *args, **kwargs):
|
|
202
220
|
caller_module = self._get_caller()
|
|
203
221
|
if self._get_effective_level(caller_module) <= logging.DEBUG:
|
|
@@ -229,4 +247,59 @@ class Logger:
|
|
|
229
247
|
self._logger.critical(f"[{caller_module}] {msg}", *args, **kwargs)
|
|
230
248
|
raise Exception(msg)
|
|
231
249
|
|
|
250
|
+
|
|
251
|
+
class LoggerChild:
|
|
252
|
+
"""
|
|
253
|
+
子日志记录器
|
|
254
|
+
|
|
255
|
+
用于创建具有特定名称的子日志记录器,仅改变模块名称,其他功能全部委托给父日志记录器
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
def __init__(self, parent_logger: Logger, name: str):
|
|
259
|
+
"""
|
|
260
|
+
初始化子日志记录器
|
|
261
|
+
|
|
262
|
+
:param parent_logger: 父日志记录器实例
|
|
263
|
+
:param name: 子日志记录器名称
|
|
264
|
+
"""
|
|
265
|
+
self._parent = parent_logger
|
|
266
|
+
self._name = name
|
|
267
|
+
|
|
268
|
+
def debug(self, msg, *args, **kwargs):
|
|
269
|
+
if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.DEBUG:
|
|
270
|
+
self._parent._save_in_memory(self._name, msg)
|
|
271
|
+
self._parent._logger.debug(f"[{self._name}] {msg}", *args, **kwargs)
|
|
272
|
+
|
|
273
|
+
def info(self, msg, *args, **kwargs):
|
|
274
|
+
if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.INFO:
|
|
275
|
+
self._parent._save_in_memory(self._name, msg)
|
|
276
|
+
self._parent._logger.info(f"[{self._name}] {msg}", *args, **kwargs)
|
|
277
|
+
|
|
278
|
+
def warning(self, msg, *args, **kwargs):
|
|
279
|
+
if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.WARNING:
|
|
280
|
+
self._parent._save_in_memory(self._name, msg)
|
|
281
|
+
self._parent._logger.warning(f"[{self._name}] {msg}", *args, **kwargs)
|
|
282
|
+
|
|
283
|
+
def error(self, msg, *args, **kwargs):
|
|
284
|
+
if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.ERROR:
|
|
285
|
+
self._parent._save_in_memory(self._name, msg)
|
|
286
|
+
self._parent._logger.error(f"[{self._name}] {msg}", *args, **kwargs)
|
|
287
|
+
|
|
288
|
+
def critical(self, msg, *args, **kwargs):
|
|
289
|
+
if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.CRITICAL:
|
|
290
|
+
self._parent._save_in_memory(self._name, msg)
|
|
291
|
+
self._parent._logger.critical(f"[{self._name}] {msg}", *args, **kwargs)
|
|
292
|
+
raise Exception(msg)
|
|
293
|
+
|
|
294
|
+
def get_child(self, child_name: str):
|
|
295
|
+
"""
|
|
296
|
+
获取子日志记录器的子记录器
|
|
297
|
+
|
|
298
|
+
:param child_name: 子模块名称
|
|
299
|
+
:return: LoggerChild 子日志记录器实例
|
|
300
|
+
"""
|
|
301
|
+
full_child_name = f"{self._name}.{child_name}"
|
|
302
|
+
return LoggerChild(self._parent, full_child_name)
|
|
303
|
+
|
|
304
|
+
|
|
232
305
|
logger = Logger()
|