1
1
mirror of https://github.com/KenanZhu/AutoLibrary.git synced 2026-06-17 23:13:03 +08:00

feat(MsgBase, gui, operators): 增强日志输出功能

- 为 _showTrace 方法添加 no_log 参数,支持控制日志写入
- 在主窗口各关键操作点添加日志输出
- 优化错误信息输出策略,分离 trace 和 log 输出
- 改进配置目录初始化过程的日志记录
This commit is contained in:
2026-03-18 12:46:37 +08:00
parent e481824344
commit 02463f087e
10 changed files with 94 additions and 38 deletions
+3 -2
View File
@@ -70,12 +70,13 @@ class MsgBase:
def _showTrace(
self,
msg: str,
level: int = logging.INFO
level: int = logging.INFO,
no_log: bool = False
):
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
self._output_queue.put(f"{timestamp}-[{self._class_name:<15}] : {msg}")
if self._logger:
if self._logger and not no_log:
self._logger.log(level, msg)
+9 -2
View File
@@ -59,6 +59,7 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.connectSignals()
self.startMsgPolling()
self.startTimerTaskPolling()
self._showLog("主窗口初始化完成")
def modifyUi(
@@ -186,6 +187,7 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
if self.__alConfigWidget:
self.__alConfigWidget.close()
# the config widget is already deleted in the 'self.onConfigWidgetClosed'
self._showLog("主窗口关闭")
QMainWindow.closeEvent(self, event)
@@ -300,6 +302,7 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.__alConfigWidget = None
self.__config_paths = ConfigManager.getValidateAutomationConfigPaths()
self.setControlButtons(True, None, None)
self._showLog("配置窗口已关闭,配置文件路径已更新")
@Slot(dict)
def onTimerTaskIsReady(
@@ -347,6 +350,7 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.__alTimerTaskManageWidget.raise_()
self.__alTimerTaskManageWidget.activateWindow()
self.TimerTaskManageWidgetButton.setEnabled(False)
self._showLog("打开定时任务管理窗口")
@Slot()
def onConfigButtonClicked(
@@ -360,6 +364,7 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.__alConfigWidget.raise_()
self.__alConfigWidget.activateWindow()
self.ConfigButton.setEnabled(False)
self._showLog("打开配置窗口")
@Slot()
def onStartButtonClicked(
@@ -376,6 +381,7 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
self.__auto_lib_thread.autoLibWorkerIsFinished.connect(self.onStopButtonClicked)
self.__auto_lib_thread.autoLibWorkerFinishedWithError.connect(self.onStopButtonClicked)
self.__auto_lib_thread.start()
self._showLog("开始手动执行任务")
@Slot()
def onStopButtonClicked(
@@ -383,14 +389,15 @@ class ALMainWindow(MsgBase, QMainWindow, Ui_ALMainWindow):
):
if self.__auto_lib_thread:
self._showTrace("正在停止操作......")
self._showTrace("正在停止操作......", no_log=True)
self.__auto_lib_thread.wait(2000)
self._showTrace("操作已停止")
self._showTrace("操作已停止", no_log=True)
self.__auto_lib_thread.autoLibWorkerIsFinished.disconnect(self.onStopButtonClicked)
self.__auto_lib_thread.autoLibWorkerFinishedWithError.disconnect(self.onStopButtonClicked)
self.__auto_lib_thread.deleteLater()
self.__auto_lib_thread = None
self.setControlButtons(None, False, True)
self._showLog("任务已停止")
@Slot()
def onSendButtonClicked(
+29 -11
View File
@@ -44,9 +44,11 @@ class AutoLibWorker(MsgBase, QThread):
current_time = time.strftime("%H:%M", time.localtime())
if current_time >= "23:30" or current_time <= "07:30":
self._showTrace(
"当前时间不在图书馆开放时间内, 请在 07:30 - 23:30 之间尝试"
"当前时间不在图书馆开放时间内, 请在 07:30 - 23:30 之间尝试",
self.TraceLevel.WARNING
)
return False
self._showLog(f"时间检查通过, 当前时间: {current_time}", self.TraceLevel.INFO)
return True
@@ -57,8 +59,12 @@ class AutoLibWorker(MsgBase, QThread):
if not all(
os.path.exists(path) for path in self.__config_paths.values()
):
self._showTrace("配置文件路径不存在, 请检查配置文件路径是否正确")
self._showTrace(
"配置文件路径不存在, 请检查配置文件路径是否正确",
self.TraceLevel.ERROR
)
return False
self._showLog(f"配置文件路径检查通过, 路径: {self.__config_paths}", self.TraceLevel.INFO)
return True
@@ -67,22 +73,28 @@ class AutoLibWorker(MsgBase, QThread):
) -> bool:
self._showTrace(
f"正在加载配置文件, 运行配置文件路径: {self.__config_paths["run"]}"
f"正在加载配置文件, 运行配置文件路径: {self.__config_paths["run"]}",
no_log=True
)
self.__run_config = JSONReader(self.__config_paths["run"]).data()
self._showTrace(
f"正在加载配置文件, 用户配置文件路径: {self.__config_paths["user"]}"
f"正在加载配置文件, 用户配置文件路径: {self.__config_paths["user"]}",
no_log=True
)
self.__user_config = JSONReader(self.__config_paths["user"]).data()
if self.__run_config is None or self.__user_config is None:
self._showTrace("配置文件加载失败, 请检查配置文件是否正确")
self._showTrace("配置文件加载失败, 请检查配置文件是否正确")
self._showTrace(
"配置文件加载失败, 请检查配置文件是否正确",
self.TraceLevel.ERROR
)
return False
if not self.__user_config.get("groups"):
self._showTrace(
"用户配置文件中无有效任务组, 请检查用户配置文件是否正确"
"用户配置文件中无有效任务组, 请检查用户配置文件是否正确",
self.TraceLevel.WARNING
)
return False
self._showLog(f"配置文件加载成功, 任务组数量: {len(self.__user_config.get('groups', []))}", self.TraceLevel.INFO)
return True
@@ -108,14 +120,17 @@ class AutoLibWorker(MsgBase, QThread):
groups = self.__user_config.get("groups")
for group in groups:
if not group["enabled"]:
self._showTrace(f"任务组 {group["name"]} 已跳过")
self._showTrace(f"任务组 {group["name"]} 已跳过", no_log=True)
continue
self._showTrace(f"正在运行任务组 {group["name"]}")
self._showTrace(f"正在运行任务组 {group["name"]}", no_log=True)
auto_lib.run(
{ "users": group.get("users", []) }
)
except Exception as e:
self._showTrace(f"AutoLibrary 运行时发生异常 : {e}")
self._showTrace(
f"AutoLibrary 运行时发生异常 : {e}",
self.TraceLevel.ERROR
)
self.autoLibWorkerFinishedWithError.emit()
return
if auto_lib:
@@ -154,7 +169,10 @@ class TimerTaskWorker(AutoLibWorker):
self
):
self._showTrace(f"定时任务 {self.__timer_task['name']} 运行时发生异常")
self._showTrace(
f"定时任务 {self.__timer_task['name']} 运行时发生异常",
self.TraceLevel.ERROR
)
self.timerTaskWorkerIsFinished.emit(True, self.__timer_task)
@Slot()
+24 -8
View File
@@ -54,7 +54,7 @@ class AutoLib(MsgBase):
self
) -> bool:
self._showTrace("正在初始化浏览器驱动......")
self._showTrace("正在初始化浏览器驱动......", no_log=True)
web_driver_config = self.__run_config.get("web_driver", None)
self.__driver_type = web_driver_config.get("driver_type")
@@ -126,7 +126,7 @@ class AutoLib(MsgBase):
service = ChromeService(executable_path=self.__driver_path)
self.__driver = webdriver.Chrome(service=service, options=driver_options)
case "firefox":
self._showTrace(f"Firefox 浏览器驱动初始化略慢, 请耐心等待...")
self._showTrace(f"Firefox 浏览器驱动初始化略慢, 请耐心等待...", no_log=True)
service = FirefoxService(executable_path=self.__driver_path)
self.__driver = webdriver.Firefox(service=service, options=driver_options)
case _: # actually will not happen, beacuse we have checked it at the initlization
@@ -245,8 +245,10 @@ class AutoLib(MsgBase):
else:
self._showTrace(f"用户 {username} 无法预约,已跳过")
result = 2
# checkin
if run_mode["auto_checkin"] and result != 1:
last_result = result
if run_mode["auto_checkin"] and last_result != 1:
if self.__lib_checker.canCheckin():
if self.__lib_checkin.checkin(username):
result = 0
@@ -255,8 +257,12 @@ class AutoLib(MsgBase):
else:
self._showTrace(f"用户 {username} 无法签到,已跳过")
result = 2
if last_result == 0: # partly success
result = 0
# renewal
if run_mode["auto_renewal"] and result != 1:
last_result = result
if run_mode["auto_renewal"] and last_result != 1:
can_renew, record = self.__lib_checker.canRenew()
if can_renew:
if self.__lib_renew.renew(username, record, reserve_info):
@@ -264,12 +270,18 @@ class AutoLib(MsgBase):
self._showTrace(f"用户 {username} 续约成功 !")
result = 0
else:
result = 1
if result != 1: # partly success
result = 0
else:
result = 1
else:
result = 1
else:
self._showTrace(f"用户 {username} 无法续约,已跳过")
result = 2
if last_result == 0: # partly success
result = 0
# logout
if not self.__lib_logout.logout(
username
@@ -294,7 +306,8 @@ class AutoLib(MsgBase):
for user in users:
user_counter["current"] += 1
self._showTrace(
f"正在处理第 {user_counter["current"]}/{len(users)} 个用户: {user["username"]}......"
f"正在处理第 {user_counter["current"]}/{len(users)} 个用户: {user["username"]}......",
no_log=True
)
if not user["enabled"]:
self._showTrace(f"用户 {user["username"]} 已跳过")
@@ -333,11 +346,14 @@ class AutoLib(MsgBase):
if self.__driver:
if self.__driver_type.lower() == "firefox":
self._showTrace(f"Firefox 浏览器驱动关闭略慢, 请耐心等待...")
self._showTrace(
f"Firefox 浏览器驱动关闭略慢, 请耐心等待...",
no_log=True
)
self.__driver.quit()
self.__driver = None
self._showTrace(f"浏览器驱动已关闭")
return True
else:
self._showTrace(f"浏览器驱动未初始化, 无需关闭")
self._showTrace(f"浏览器驱动未初始化, 无需关闭", no_log=True)
return False
+3 -2
View File
@@ -213,7 +213,7 @@ class LibChecker(LibOperator):
if wanted_date is None:
self._showTrace("日期未指定, 无法检查当前预约状态", self.TraceLevel.WARNING)
return None
self._showTrace(f"正在检查用户在 {wanted_date} 是否有预约状态为 {wanted_status} 的预约记录......")
self._showTrace(f"正在检查用户在 {wanted_date} 是否有预约状态为 {wanted_status} 的预约记录......", no_log=True)
checked_count = 0
max_check_times = 6 # we only check (4*(6-1)=)20 reservations, the last time cant be checked
@@ -245,7 +245,8 @@ class LibChecker(LibOperator):
self._showTrace(
f"寻找到用户第 {checked_count} 条状态为 {wanted_status} 的预约记录, "
f"详细信息: {record["date"]} "
f"{record["time"]["begin"]} - {record["time"]["end"]} {record["info"]["location"]}"
f"{record["time"]["begin"]} - {record["time"]["end"]} {record["info"]["location"]}",
no_log=True
)
return record
if not self.__showMoreReserveRecords():
+3 -3
View File
@@ -107,7 +107,7 @@ class LibCheckin(LibOperator):
result = self.__driver.execute_script(script)
time.sleep(0.1)
if result:
self._showTrace("签到按钮已启用")
self._showTrace("签到按钮已启用", no_log=True)
else:
self._showTrace("签到按钮启用失败", self.TraceLevel.WARNING)
return result
@@ -129,13 +129,13 @@ class LibCheckin(LibOperator):
self._showTrace(f"用户 {username} 签到界面加载失败 !", self.TraceLevel.ERROR)
return False
if "disabled" in checkin_btn.get_attribute("class"):
self._showTrace("签到按钮不可用, 可能不在场馆内, 正在尝试启用......")
self._showTrace("签到按钮不可用, 可能不在场馆内, 正在尝试启用......", no_log=True)
if not self.__enableCheckinBtn():
self._showTrace(f"签到按钮启用失败 !", self.TraceLevel.ERROR)
return False
checkin_btn.click()
if self._waitResponseLoad():
self._showTrace(f"用户 {username} 签到成功 !")
self._showTrace(f"用户 {username} 签到成功 !", no_log=True)
return True
else:
self._showTrace(f"用户 {username} 签到失败 !", self.TraceLevel.ERROR)
+6 -6
View File
@@ -91,7 +91,7 @@ class LibLogin(LibOperator):
captcha_img = base64.b64decode(base64_str)
captcha_text = self.__ddddocr.classification(captcha_img)
captcha_text = ''.join(filter(str.isalnum, captcha_text)).lower()
self._showTrace(f"识别到验证码为 : '{captcha_text}'")
self._showTrace(f"识别到验证码为 : '{captcha_text}'", no_log=True)
if len(captcha_text) != 4:
self._showLog("识别到的验证码长度不等于 4 个字符 !", self.TraceLevel.WARNING)
raise Exception("识别到的验证码长度不等于 4 个字符 !")
@@ -109,7 +109,7 @@ class LibLogin(LibOperator):
try:
self._showMsg("请输入验证码:")
captcha_text = self._waitMsg(timeout=15)
self._showTrace(f"输入的验证码为 : '{captcha_text}'")
self._showTrace(f"输入的验证码为 : '{captcha_text}'", no_log=True)
if len(captcha_text) != 4:
self._showLog("输入的验证码长度不等于 4 个字符 !", self.TraceLevel.WARNING)
raise Exception("输入的验证码长度不等于 4 个字符 !")
@@ -125,7 +125,7 @@ class LibLogin(LibOperator):
# refresh captcha
try:
self._showTrace("刷新验证码......")
self._showTrace("刷新验证码......", no_log=True)
self.__driver.find_element(
By.ID, "loadImgId"
).click()
@@ -145,7 +145,7 @@ class LibLogin(LibOperator):
if auto_captcha:
captcha_text = self.__autoRecognizeCaptcha()
else:
self._showTrace(f"用户未配置自动识别验证码, 请手动输入验证码 !")
self._showTrace(f"用户未配置自动识别验证码, 请手动输入验证码 !", no_log=True)
captcha_text = self.__manualRecognizeCaptcha()
if captcha_text:
return captcha_text
@@ -187,7 +187,7 @@ class LibLogin(LibOperator):
return False
# begin login process
for attempt in range(max_attempts):
self._showTrace(f"用户 {username}{attempt + 1} 次尝试登录......")
self._showTrace(f"用户 {username}{attempt + 1} 次尝试登录......", no_log=True)
if not self.__fillLogInElements(
username,
password,
@@ -198,7 +198,7 @@ class LibLogin(LibOperator):
continue
if not self.__fillCaptchaElement(captcha_text):
continue
self._showTrace("尝试登录...")
self._showTrace("尝试登录...", no_log=True)
try:
self.__driver.find_element(
By.XPATH,
+3 -2
View File
@@ -61,7 +61,7 @@ class LibRenew(LibTimeSelector):
result_message = result_message.text.strip()
self._showTrace(f"\n"\
f" 续约失败 !\n"\
f" {result_message}")
f" {result_message}", no_log=True)
return False
try:
WebDriverWait(self.__driver, 2).until(
@@ -186,7 +186,8 @@ class LibRenew(LibTimeSelector):
self._showTrace(f"用户 {username} 续约界面加载失败 !", self.TraceLevel.ERROR)
return False
if "disabled" in renew_btn.get_attribute("class"):
self._showTrace(f"用户 {username} 续约按钮不可用, 可能不在场馆内, 请连接图书馆网络后重试")
self._showLog(f"用户 {username} 续约按钮不可用, 可能不在场馆内")
self._showTrace(f"用户 {username} 续约按钮不可用, 可能不在场馆内, 请连接图书馆网络后重试", no_log=True)
return False
renew_btn.click()
if not self.__waitRenewDialog():
+8 -2
View File
@@ -125,9 +125,14 @@ class LibReserve(LibTimeSelector):
except ValueError as e:
self._showTrace(
f"预约信息错误 ! : {e}, "\
f"由于缺少必要的预约信息, 无法开始预约流程, 请检查预约信息是否完整",
f"由于缺少必要的预约信息, 无法开始预约流程",
self.TraceLevel.ERROR
)
self._showTrace(
f"预约信息错误 ! : {e}, "\
f"由于缺少必要的预约信息, 无法开始预约流程, 请检查预约信息是否完整",
no_log=True
)
return False
@@ -481,7 +486,8 @@ class LibReserve(LibTimeSelector):
seat_status = seat_link.get_attribute("title")
self._showTrace(f"座位 {seat_id} 选择成功 ! : 当前状态 - '{seat_status}'")
return True
self._showTrace(f"座位 {seat_id} 在该楼层区域中不存在, 请检查座位号是否正确", self.TraceLevel.WARNING)
self._showLog(f"座位 {seat_id} 在该楼层区域中不存在", self.TraceLevel.WARNING)
self._showTrace(f"座位 {seat_id} 在该楼层区域中不存在, 请检查座位号是否正确", no_log=True)
except:
self._showTrace(f"座位选择失败 !", self.TraceLevel.ERROR)
return False
+6
View File
@@ -18,15 +18,21 @@ from utils.LogManager import instance as logInstance
def initializeConfigManager(
) -> bool:
logger = logInstance().getLogger("AppInitializer")
app_dir = QStandardPaths.writableLocation(QStandardPaths.StandardLocation.AppDataLocation)
old_config_dir = os.path.join(app_dir, "config")
new_config_dir = os.path.join(app_dir, "configs")
if QDir(old_config_dir).exists(): # old config dir exists
#we rename it to compatible with new version
logger.info("存在旧配置目录 %s,将其重命名为 %s", old_config_dir, new_config_dir)
if not QDir().rename(old_config_dir, new_config_dir):
logger.error("重命名旧配置目录 %s%s 失败", old_config_dir, new_config_dir)
return False
elif not QDir(new_config_dir).exists():
logger.info("初始化配置目录 %s", new_config_dir)
if not QDir().mkpath(new_config_dir):
logger.error("创建配置目录 %s 失败", new_config_dir)
return False
configInstance(new_config_dir)
return True