diff --git a/repo/js/README.md b/repo/js/1Remote_RDP_Autoreconnection/README.md
similarity index 98%
rename from repo/js/README.md
rename to repo/js/1Remote_RDP_Autoreconnection/README.md
index 622546ac..483e9a57 100644
--- a/repo/js/README.md
+++ b/repo/js/1Remote_RDP_Autoreconnection/README.md
@@ -1,89 +1,89 @@
-# 📋 日志监控与自动重连脚本说明
-
-**作者:火山**
-
-## 📌 功能介绍
-该脚本用于实时监控1Remote的日志文件,当检测到远程连接断开(日志中出现`OnRdpClientDisconnected`警告)时,自动执行重连操作,保障远程连接的稳定性。
-
-### ⚡⚡⚡❗ 重要提醒:这不是JS脚本 ❗⚡⚡⚡
-### ⚡⚡⚡❗ 绝对不要不看完就直接运行 ❗⚡⚡⚡
-### ⚡⚡⚡❗ 再次强调:这不是可执行的JS脚本 ❗⚡⚡⚡
-
-
-## 🚀 环境要求
-- **操作系统**:Windows(脚本依赖Windows特定快捷键操作)
-- **Python版本**:Python 3.6及以上
- (检查方法:按下`Win+R`输入`cmd`,在命令行中执行`python --version`)
-
-
-## 🔧 安装依赖(重要!小白必看)
-1. **以管理员身份打开命令提示符(CMD)**:
- - 方法1:按下`Win + R`输入`cmd`,按住`Ctrl + Shift`同时点击「确定」
- - 方法2:开始菜单搜索「命令提示符」,右键选择「以管理员身份运行」
-
-2. **执行安装命令**:
- 在管理员CMD窗口中输入以下命令并回车,等待安装完成(出现`Successfully installed`字样即为成功):
- ```
- pip install pyautogui watchdog
- ```
-
-
-## 📂 文件说明
-| 文件名 | 作用描述 |
-|----------------------|--------------------------------------------------------------------------|
-| `log_monitor.py` | 核心监控程序,负责监控日志文件变化、检测断开事件并触发重连操作 |
-| `autoreconnection.py`| 重连操作脚本,通过模拟键盘快捷键(Win+D、Alt+M等)执行自动重连 |
-| `config.json` | 配置文件,存储1Remote日志文件所在目录(示例:`C:\...\1Remote-...\.logs`)|
-| `监控异常.txt` | 程序运行日志,记录操作过程、错误信息及重连状态(用于问题排查) |
-
-
-## 🔍 首次使用步骤
-1. 确保已安装Python 3.6及以上版本并完成依赖安装
-2. 双击运行`log_monitor.py`或在CMD中执行:
- ```
- python log_monitor.py
- ```
-3. 首次运行将引导配置日志目录:
- - 日志文件命名格式为 `1Remote.log_YYYYMMDD.md`(按日期生成)
- - 请输入1Remote日志所在目录的完整路径(例如 `.logs` 文件夹路径)
-
-
-## ⚙️ 配置说明
-配置信息存储在`config.json`中,格式如下:
-```json
-{
- "log_dir": "C:\\Users\\Administrator\\Desktop\\1Remote-1.2.0-net9-x64\\.logs"
-}
-```
-- **修改日志目录**:
- 1. 运行`log_monitor.py`,程序会引导配置
- 2. 或删除`config.json`后重新运行`log_monitor.py`,程序会重新引导配置
-
-
-## 🖥️ 使用方法
-1. 运行`log_monitor.py`后,程序将自动监控日志文件
-2. 当检测到连接断开时,自动执行以下操作(通过`autoreconnection.py`实现):
- - 按`Win+D`返回桌面
- - 按`Alt+M`组合键(按住Alt键后按M键,保持0.5秒后松开)
- - 连续按两次回车键(间隔0.3秒)
-3. 运行状态会同时显示在控制台和`监控异常.txt`中
-
-
-## ⚠️ 注意事项
-1. 确保1Remote程序正常运行且日志文件能正常生成(否则会提示"未找到日志文件")
-2. 脚本运行时会模拟键盘操作,建议避免手动操作鼠标键盘,以免干扰流程
-3. 重连逻辑:
- - 最多尝试3次重连,失败则暂停重试
- - 单次重连超时时间为30秒,20秒内未检测到成功标志会自动重试
-4. 支持跨天日志文件切换(因日志按日期命名)
-5. 所有操作记录(含错误信息)均保存在`监控异常.txt`,便于排查问题
-6. 确保Alt+M的1Remote快捷指令能够正常执行,建议先双击`autoreconnection.py`查看效果
-7. 确保Win+D的Windows快捷键能指向正确是显示器(双屏会多一步选择哪块屏幕的操作,建议问AI修改一下`autoreconnection.py`中的操作)
-
-
-## ❓ 常见问题
-| 问题现象 | 解决方法 |
-|---------------------------|--------------------------------------------------------------------------|
-| 提示"未找到日志文件" | 1. 检查`config.json`中日志目录是否正确
2. 确认1Remote已运行并生成当天日志(`1Remote.log_YYYYMMDD.md`) |
-| 重连操作无反应 | 1. 检查`autoreconnection.py`是否与`log_monitor.py`在同一目录
2. 手动测试快捷键(Win+D、Alt+M)是否有效
3. 重新执行管理员CMD下的依赖安装命令 |
+# 📋 日志监控与自动重连脚本说明
+
+**作者:火山**
+
+## 📌 功能介绍
+该脚本用于实时监控1Remote的日志文件,当检测到远程连接断开(日志中出现`OnRdpClientDisconnected`警告)时,自动执行重连操作,保障远程连接的稳定性。
+
+### ⚡⚡⚡❗ 重要提醒:这不是JS脚本 ❗⚡⚡⚡
+### ⚡⚡⚡❗ 绝对不要不看完就直接运行 ❗⚡⚡⚡
+### ⚡⚡⚡❗ 再次强调:这不是可执行的JS脚本 ❗⚡⚡⚡
+
+
+## 🚀 环境要求
+- **操作系统**:Windows(脚本依赖Windows特定快捷键操作)
+- **Python版本**:Python 3.6及以上
+ (检查方法:按下`Win+R`输入`cmd`,在命令行中执行`python --version`)
+
+
+## 🔧 安装依赖(重要!小白必看)
+1. **以管理员身份打开命令提示符(CMD)**:
+ - 方法1:按下`Win + R`输入`cmd`,按住`Ctrl + Shift`同时点击「确定」
+ - 方法2:开始菜单搜索「命令提示符」,右键选择「以管理员身份运行」
+
+2. **执行安装命令**:
+ 在管理员CMD窗口中输入以下命令并回车,等待安装完成(出现`Successfully installed`字样即为成功):
+ ```
+ pip install pyautogui watchdog
+ ```
+
+
+## 📂 文件说明
+| 文件名 | 作用描述 |
+|----------------------|--------------------------------------------------------------------------|
+| `log_monitor.py` | 核心监控程序,负责监控日志文件变化、检测断开事件并触发重连操作 |
+| `autoreconnection.py`| 重连操作脚本,通过模拟键盘快捷键(Win+D、Alt+M等)执行自动重连 |
+| `config.json` | 配置文件,存储1Remote日志文件所在目录(示例:`C:\...\1Remote-...\.logs`)|
+| `监控异常.txt` | 程序运行日志,记录操作过程、错误信息及重连状态(用于问题排查) |
+
+
+## 🔍 首次使用步骤
+1. 确保已安装Python 3.6及以上版本并完成依赖安装
+2. 双击运行`log_monitor.py`或在CMD中执行:
+ ```
+ python log_monitor.py
+ ```
+3. 首次运行将引导配置日志目录:
+ - 日志文件命名格式为 `1Remote.log_YYYYMMDD.md`(按日期生成)
+ - 请输入1Remote日志所在目录的完整路径(例如 `.logs` 文件夹路径)
+
+
+## ⚙️ 配置说明
+配置信息存储在`config.json`中,格式如下:
+```json
+{
+ "log_dir": "C:\\Users\\Administrator\\Desktop\\1Remote-1.2.0-net9-x64\\.logs"
+}
+```
+- **修改日志目录**:
+ 1. 运行`log_monitor.py`,程序会引导配置
+ 2. 或删除`config.json`后重新运行`log_monitor.py`,程序会重新引导配置
+
+
+## 🖥️ 使用方法
+1. 运行`log_monitor.py`后,程序将自动监控日志文件
+2. 当检测到连接断开时,自动执行以下操作(通过`autoreconnection.py`实现):
+ - 按`Win+D`返回桌面
+ - 按`Alt+M`组合键(按住Alt键后按M键,保持0.5秒后松开)
+ - 连续按两次回车键(间隔0.3秒)
+3. 运行状态会同时显示在控制台和`监控异常.txt`中
+
+
+## ⚠️ 注意事项
+1. 确保1Remote程序正常运行且日志文件能正常生成(否则会提示"未找到日志文件")
+2. 脚本运行时会模拟键盘操作,建议避免手动操作鼠标键盘,以免干扰流程
+3. 重连逻辑:
+ - 最多尝试3次重连,失败则暂停重试
+ - 单次重连超时时间为30秒,20秒内未检测到成功标志会自动重试
+4. 支持跨天日志文件切换(因日志按日期命名)
+5. 所有操作记录(含错误信息)均保存在`监控异常.txt`,便于排查问题
+6. 确保Alt+M的1Remote快捷指令能够正常执行,建议先双击`autoreconnection.py`查看效果
+7. 确保Win+D的Windows快捷键能指向正确是显示器(双屏会多一步选择哪块屏幕的操作,建议问AI修改一下`autoreconnection.py`中的操作)
+
+
+## ❓ 常见问题
+| 问题现象 | 解决方法 |
+|---------------------------|--------------------------------------------------------------------------|
+| 提示"未找到日志文件" | 1. 检查`config.json`中日志目录是否正确
2. 确认1Remote已运行并生成当天日志(`1Remote.log_YYYYMMDD.md`) |
+| 重连操作无反应 | 1. 检查`autoreconnection.py`是否与`log_monitor.py`在同一目录
2. 手动测试快捷键(Win+D、Alt+M)是否有效
3. 重新执行管理员CMD下的依赖安装命令 |
| 程序启动失败 | 1. 查看`监控异常.txt`获取错误详情
2. 检查Python版本是否符合要求(3.6及以上) |
\ No newline at end of file
diff --git a/repo/js/autoreconnection.py b/repo/js/1Remote_RDP_Autoreconnection/autoreconnection.py
similarity index 96%
rename from repo/js/autoreconnection.py
rename to repo/js/1Remote_RDP_Autoreconnection/autoreconnection.py
index 93b24292..82b75283 100644
--- a/repo/js/autoreconnection.py
+++ b/repo/js/1Remote_RDP_Autoreconnection/autoreconnection.py
@@ -1,24 +1,24 @@
-import pyautogui
-import time
-
-print("正在执行会话关闭后操作...")
-time.sleep(2)
-# 返回Windows桌面(Win+D)
-pyautogui.hotkey('winleft', 'd') # 更通用的Win+D组合键
-time.sleep(1) # 等待1秒
-
-# 按下Alt+M键(半秒后松开)
-pyautogui.keyDown('alt') # 按住Alt键
-pyautogui.press('m') # 按M键
-time.sleep(0.5) # 精确等待0.5秒(半秒)
-pyautogui.keyUp('alt') # 松开Alt键
-pyautogui.keyUp('m') # 松开M键(确保按键无粘连)
-
-time.sleep(0.1) # 等待0.1秒
-
-# 按两次回车键,间隔0.3秒
-pyautogui.press('enter')
-time.sleep(0.3) # 等待0.3秒
-pyautogui.press('enter')
-
+import pyautogui
+import time
+
+print("正在执行会话关闭后操作...")
+time.sleep(2)
+# 返回Windows桌面(Win+D)
+pyautogui.hotkey('winleft', 'd') # 更通用的Win+D组合键
+time.sleep(1) # 等待1秒
+
+# 按下Alt+M键(半秒后松开)
+pyautogui.keyDown('alt') # 按住Alt键
+pyautogui.press('m') # 按M键
+time.sleep(0.5) # 精确等待0.5秒(半秒)
+pyautogui.keyUp('alt') # 松开Alt键
+pyautogui.keyUp('m') # 松开M键(确保按键无粘连)
+
+time.sleep(0.1) # 等待0.1秒
+
+# 按两次回车键,间隔0.3秒
+pyautogui.press('enter')
+time.sleep(0.3) # 等待0.3秒
+pyautogui.press('enter')
+
print("操作完成!")
\ No newline at end of file
diff --git a/repo/js/log_monitor.py b/repo/js/1Remote_RDP_Autoreconnection/log_monitor.py
similarity index 97%
rename from repo/js/log_monitor.py
rename to repo/js/1Remote_RDP_Autoreconnection/log_monitor.py
index e2d402df..82b7e045 100644
--- a/repo/js/log_monitor.py
+++ b/repo/js/1Remote_RDP_Autoreconnection/log_monitor.py
@@ -1,368 +1,368 @@
-import os
-import sys
-import time
-import json
-import logging
-import subprocess
-from datetime import datetime
-from watchdog.observers import Observer
-from watchdog.events import FileSystemEventHandler
-
-# 配置参数
-SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-CONFIG_FILE = os.path.join(SCRIPT_DIR, "config.json")
-LOG_MONITOR_PATH = os.path.join(SCRIPT_DIR, "监控异常.txt")
-ENCODING = "utf-8"
-RECONNECT_SCRIPT_NAME = "autoreconnection.py"
-
-# 创建日志目录(如果不存在)
-os.makedirs(SCRIPT_DIR, exist_ok=True)
-
-# 初始化日志系统
-logging.basicConfig(
- filename=LOG_MONITOR_PATH,
- level=logging.INFO,
- format='%(asctime)s [%(levelname)s] %(message)s',
- datefmt='%Y-%m-%d %H:%M:%S'
-)
-# 同时输出到控制台
-console = logging.StreamHandler()
-console.setLevel(logging.INFO)
-formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
-console.setFormatter(formatter)
-logging.getLogger().addHandler(console)
-
-# 记录状态
-last_position = 0
-processed_times = {}
-last_processed_date = None
-reconnect_count = 0
-current_log_file = None
-
-# 重启验证相关变量
-reconnect_attempts = 0 # 当前重启尝试次数
-max_reconnect_attempts = 3 # 最大尝试次数
-reconnect_in_progress = False # 标记是否有重启操作正在进行
-reconnect_start_time = 0 # 重启开始时间戳
-reconnect_success_detected = False # 是否检测到成功重启的日志
-
-def configure_log_directory():
- """引导用户配置日志目录"""
- print("="*50)
- print("日志监控程序配置")
- print("="*50)
- print("请指定1Remote日志文件所在的目录")
- print("日志文件命名格式为: 1Remote.log_YYYYMMDD.md")
- print("="*50)
-
- while True:
- log_dir = input("请输入日志目录完整路径: ").strip()
-
- # 验证路径是否存在
- if not os.path.exists(log_dir):
- print(f"错误: 路径不存在 - {log_dir}")
- continue
-
- # 验证是否是目录
- if not os.path.isdir(log_dir):
- print(f"错误: 这不是一个目录 - {log_dir}")
- continue
-
- # 验证目录中是否有日志文件
- log_files = [f for f in os.listdir(log_dir)
- if f.startswith("1Remote.log_") and f.endswith(".md")]
-
- if not log_files:
- print(f"警告: 目录中没有找到日志文件 - {log_dir}")
- choice = input("是否继续使用此目录? (y/n): ").strip().lower()
- if choice != 'y':
- continue
-
- return log_dir
-
-def load_config():
- """从配置文件加载日志目录"""
- if not os.path.exists(CONFIG_FILE):
- return None
-
- try:
- with open(CONFIG_FILE, 'r', encoding=ENCODING) as f:
- config = json.load(f)
- log_dir = config.get('log_dir')
-
- # 验证目录是否存在
- if not os.path.isdir(log_dir):
- logging.error(f"配置文件中的目录不存在: {log_dir}")
- return None
-
- return log_dir
-
- except (json.JSONDecodeError, UnicodeDecodeError):
- logging.error("配置文件损坏,请重新配置")
- return None
- except Exception as e:
- logging.error(f"加载配置失败: {str(e)}")
- return None
-
-def save_config(log_dir):
- """保存日志目录到配置文件"""
- config = {'log_dir': log_dir}
- try:
- with open(CONFIG_FILE, 'w', encoding=ENCODING) as f:
- json.dump(config, f, ensure_ascii=False, indent=4)
- logging.info(f"配置已保存到: {CONFIG_FILE}")
- return True
- except Exception as e:
- logging.error(f"保存配置失败: {str(e)}")
- return False
-
-def get_today_log_file(log_dir):
- """获取指定目录下当天的日志文件"""
- today = datetime.now().strftime("%Y%m%d")
- file_pattern = f"1Remote.log_{today}.md"
-
- # 查找符合日期模式的文件
- for entry in os.scandir(log_dir):
- if entry.is_file() and entry.name == file_pattern:
- return entry.path
-
- return None
-
-def execute_reconnect():
- """执行重连操作"""
- global reconnect_count, reconnect_attempts, reconnect_in_progress, reconnect_start_time, reconnect_success_detected
-
- # 如果已经达到最大尝试次数,重置并返回失败
- if reconnect_attempts >= max_reconnect_attempts:
- logging.warning(f"【达到最大重试次数】已尝试{max_reconnect_attempts}次重启,停止重试")
- reconnect_attempts = 0
- reconnect_in_progress = False
- return False
-
- try:
- reconnect_script_path = os.path.join(SCRIPT_DIR, RECONNECT_SCRIPT_NAME)
-
- # 记录开始时间
- start_time = time.time()
- # 调用外部重启脚本
- result = subprocess.run(
- [sys.executable, reconnect_script_path],
- check=True,
- capture_output=True,
- text=True,
- timeout=30
- )
- # 计算耗时
- elapsed = time.time() - start_time
-
- # 重置成功标记,设置重启状态
- reconnect_success_detected = False
- reconnect_in_progress = True
- reconnect_start_time = time.time()
- reconnect_attempts += 1
- reconnect_count += 1
-
- logging.info(f"【重启尝试 {reconnect_attempts}/{max_reconnect_attempts}】执行成功,耗时:{elapsed:.2f}s,总重启次数:{reconnect_count}")
- return True
- except subprocess.CalledProcessError as e:
- logging.error(f"【重启失败】错误代码:{e.returncode}\nstdout: {e.stdout.strip()}\nstderr: {e.stderr.strip()}")
- except FileNotFoundError:
- logging.error(f"【重启失败】未找到重启脚本:{reconnect_script_path}")
- except subprocess.TimeoutExpired:
- logging.error(f"【重启失败】执行超时(超过30秒)")
- except Exception as e:
- logging.error(f"【重启异常】未知错误:{str(e)}", exc_info=True)
-
- reconnect_attempts += 1
- logging.warning(f"【重启尝试 {reconnect_attempts}/{max_reconnect_attempts}】失败")
- return False
-
-def process_log_line(line):
- """处理日志行并检查是否需要重启及重启是否成功"""
- global last_position, processed_times, reconnect_in_progress, reconnect_success_detected, reconnect_attempts
-
- # 检查是否是重启成功的标志日志
- if reconnect_in_progress and 'Warning' in line and '[AxMsRdpClient09Host.cs(ReConn:42)]' in line and 'RDP Host: Call ReConn' in line:
- logging.info(f"【重启成功验证】检测到成功标志: {line}")
- reconnect_success_detected = True
- reconnect_in_progress = False
- reconnect_attempts = 0 # 重置尝试次数
- return True
-
- # 原有逻辑:检查是否需要重启
- if 'Warning' in line:
- if 'OnRdpClientDisconnected' in line and not reconnect_in_progress:
- logging.warning(f"【触发重启】{line}")
- return execute_reconnect()
- elif 'ReConn:42' in line:
- logging.info(f"【忽略信号】{line}")
- else:
- logging.info(f"【未知警告】{line}")
-
- # 时间戳处理
- try:
- if '[' in line and ']' in line:
- timestamp_str = line.split(']')[0][1:]
- log_time = datetime.strptime(timestamp_str, "%H:%M:%S.%f").time()
-
- time_key = timestamp_str.replace(':', '').replace('.', '')
- if time_key not in processed_times:
- processed_times[time_key] = True
- logging.info(f"【新警告记录】{line}")
- except ValueError:
- logging.error(f"【无效时间戳】{line}")
-
- return False
-
-def monitor_log_file(log_file):
- """监控指定的日志文件"""
- global last_position, processed_times, last_processed_date
-
- try:
- # 检查是否为新的一天
- current_date = datetime.now().date()
- if current_date != last_processed_date:
- processed_times.clear()
- last_processed_date = current_date
- logging.info(f"【新的一天】开始监控{current_date}的日志文件")
-
- # 获取文件大小
- file_size = os.path.getsize(log_file)
-
- # 从上次结束位置读取新内容
- with open(log_file, 'r', encoding=ENCODING) as f:
- if file_size < last_position:
- logging.warning("【文件被截断或重置】重新从头开始读取")
- f.seek(0)
- else:
- f.seek(last_position)
- new_lines = f.read().splitlines()
-
- # 处理新增内容
- for line in new_lines:
- process_log_line(line)
-
- # 更新最后读取位置
- last_position = file_size
-
- except Exception as e:
- logging.error(f"【监控异常】{str(e)}", exc_info=True)
-
-class LogFileHandler(FileSystemEventHandler):
- """处理日志文件变化事件"""
- def __init__(self, log_dir):
- self.log_dir = log_dir
-
- def on_modified(self, event):
- global current_log_file
-
- if not event.is_directory:
- # 检查是否是当天日志文件
- today_file = get_today_log_file(self.log_dir)
- if today_file and event.src_path == today_file:
- monitor_log_file(today_file)
-
-def start_monitoring(log_dir):
- """启动日志监控(静默等待日志文件生成)"""
- global current_log_file, last_position, reconnect_in_progress, reconnect_start_time, reconnect_success_detected, reconnect_attempts
-
- # 验证监控目录是否有效(仅在启动时检查一次)
- if not os.path.isdir(log_dir):
- logging.error(f"【错误】监控目录不存在或无效: {log_dir}")
- return False
-
- try:
- while True: # 外层循环:处理跨天切换
- # 静默等待当天日志文件生成(每5秒检查一次)
- while True:
- current_log_file = get_today_log_file(log_dir)
- if current_log_file:
- logging.info(f"【找到日志文件】开始监控: {current_log_file}")
- last_position = os.path.getsize(current_log_file) # 初始化读取位置
- break
- # 无日志文件时不输出错误,仅静默等待
- time.sleep(5)
-
- # 创建事件处理器和观察器
- event_handler = LogFileHandler(log_dir)
- observer = Observer()
- observer.schedule(event_handler, path=log_dir, recursive=False)
- observer.start()
-
- # 监控循环:每1秒检查一次是否跨天或重启超时
- try:
- while True:
- # 检查重启超时
- if reconnect_in_progress:
- elapsed_time = time.time() - reconnect_start_time
- if elapsed_time > 20: # 超过20秒
- if not reconnect_success_detected:
- logging.warning(f"【重启验证超时】20秒内未检测到成功标志,尝试重新启动")
- # 停止当前监控,准备重试
- observer.stop()
- observer.join()
-
- # 如果未达到最大尝试次数,重新执行重启
- if reconnect_attempts < max_reconnect_attempts:
- execute_reconnect()
- else:
- # 达到最大尝试次数,重置状态
- reconnect_in_progress = False
- reconnect_attempts = 0
-
- # 重新启动监控
- event_handler = LogFileHandler(log_dir)
- observer = Observer()
- observer.schedule(event_handler, path=log_dir, recursive=False)
- observer.start()
- else:
- # 已检测到成功标志,重置状态
- reconnect_in_progress = False
-
- # 检查是否跨天
- today_file = get_today_log_file(log_dir)
- if today_file != current_log_file:
- # 跨天:停止当前监控,进入外层循环等待新文件
- observer.stop()
- observer.join()
- logging.info(f"【跨天切换】当前日志文件已过期,等待新日志文件...")
- break
-
- time.sleep(1) # 缩短检查间隔为1秒,提高响应速度
- except KeyboardInterrupt:
- observer.stop()
- observer.join()
- return True
- observer.join()
- except Exception as e:
- logging.error(f"【监控异常】{str(e)}", exc_info=True)
- return False
-
-if __name__ == "__main__":
- print("="*50)
- print("日志监控程序")
- print("作者:火山")
- print("="*50)
-
- # 尝试加载配置
- log_watch_dir = load_config()
-
- if not log_watch_dir:
- log_watch_dir = configure_log_directory()
- if not save_config(log_watch_dir):
- print("配置保存失败,程序退出")
- sys.exit(1)
-
- print("="*50)
- print(f"监控目录: {log_watch_dir}")
- # 修改状态提示文本,更准确反映程序状态
- print("正在监控中(等待当天日志文件生成)...")
-
- try:
- start_monitoring(log_watch_dir)
- print("监控已成功启动")
- print("作者:火山")
- except Exception as e:
- logging.error(f"【启动失败】{str(e)}", exc_info=True)
- print(f"监控启动失败: {str(e)}")
+import os
+import sys
+import time
+import json
+import logging
+import subprocess
+from datetime import datetime
+from watchdog.observers import Observer
+from watchdog.events import FileSystemEventHandler
+
+# 配置参数
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+CONFIG_FILE = os.path.join(SCRIPT_DIR, "config.json")
+LOG_MONITOR_PATH = os.path.join(SCRIPT_DIR, "监控异常.txt")
+ENCODING = "utf-8"
+RECONNECT_SCRIPT_NAME = "autoreconnection.py"
+
+# 创建日志目录(如果不存在)
+os.makedirs(SCRIPT_DIR, exist_ok=True)
+
+# 初始化日志系统
+logging.basicConfig(
+ filename=LOG_MONITOR_PATH,
+ level=logging.INFO,
+ format='%(asctime)s [%(levelname)s] %(message)s',
+ datefmt='%Y-%m-%d %H:%M:%S'
+)
+# 同时输出到控制台
+console = logging.StreamHandler()
+console.setLevel(logging.INFO)
+formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
+console.setFormatter(formatter)
+logging.getLogger().addHandler(console)
+
+# 记录状态
+last_position = 0
+processed_times = {}
+last_processed_date = None
+reconnect_count = 0
+current_log_file = None
+
+# 重启验证相关变量
+reconnect_attempts = 0 # 当前重启尝试次数
+max_reconnect_attempts = 3 # 最大尝试次数
+reconnect_in_progress = False # 标记是否有重启操作正在进行
+reconnect_start_time = 0 # 重启开始时间戳
+reconnect_success_detected = False # 是否检测到成功重启的日志
+
+def configure_log_directory():
+ """引导用户配置日志目录"""
+ print("="*50)
+ print("日志监控程序配置")
+ print("="*50)
+ print("请指定1Remote日志文件所在的目录")
+ print("日志文件命名格式为: 1Remote.log_YYYYMMDD.md")
+ print("="*50)
+
+ while True:
+ log_dir = input("请输入日志目录完整路径: ").strip()
+
+ # 验证路径是否存在
+ if not os.path.exists(log_dir):
+ print(f"错误: 路径不存在 - {log_dir}")
+ continue
+
+ # 验证是否是目录
+ if not os.path.isdir(log_dir):
+ print(f"错误: 这不是一个目录 - {log_dir}")
+ continue
+
+ # 验证目录中是否有日志文件
+ log_files = [f for f in os.listdir(log_dir)
+ if f.startswith("1Remote.log_") and f.endswith(".md")]
+
+ if not log_files:
+ print(f"警告: 目录中没有找到日志文件 - {log_dir}")
+ choice = input("是否继续使用此目录? (y/n): ").strip().lower()
+ if choice != 'y':
+ continue
+
+ return log_dir
+
+def load_config():
+ """从配置文件加载日志目录"""
+ if not os.path.exists(CONFIG_FILE):
+ return None
+
+ try:
+ with open(CONFIG_FILE, 'r', encoding=ENCODING) as f:
+ config = json.load(f)
+ log_dir = config.get('log_dir')
+
+ # 验证目录是否存在
+ if not os.path.isdir(log_dir):
+ logging.error(f"配置文件中的目录不存在: {log_dir}")
+ return None
+
+ return log_dir
+
+ except (json.JSONDecodeError, UnicodeDecodeError):
+ logging.error("配置文件损坏,请重新配置")
+ return None
+ except Exception as e:
+ logging.error(f"加载配置失败: {str(e)}")
+ return None
+
+def save_config(log_dir):
+ """保存日志目录到配置文件"""
+ config = {'log_dir': log_dir}
+ try:
+ with open(CONFIG_FILE, 'w', encoding=ENCODING) as f:
+ json.dump(config, f, ensure_ascii=False, indent=4)
+ logging.info(f"配置已保存到: {CONFIG_FILE}")
+ return True
+ except Exception as e:
+ logging.error(f"保存配置失败: {str(e)}")
+ return False
+
+def get_today_log_file(log_dir):
+ """获取指定目录下当天的日志文件"""
+ today = datetime.now().strftime("%Y%m%d")
+ file_pattern = f"1Remote.log_{today}.md"
+
+ # 查找符合日期模式的文件
+ for entry in os.scandir(log_dir):
+ if entry.is_file() and entry.name == file_pattern:
+ return entry.path
+
+ return None
+
+def execute_reconnect():
+ """执行重连操作"""
+ global reconnect_count, reconnect_attempts, reconnect_in_progress, reconnect_start_time, reconnect_success_detected
+
+ # 如果已经达到最大尝试次数,重置并返回失败
+ if reconnect_attempts >= max_reconnect_attempts:
+ logging.warning(f"【达到最大重试次数】已尝试{max_reconnect_attempts}次重启,停止重试")
+ reconnect_attempts = 0
+ reconnect_in_progress = False
+ return False
+
+ try:
+ reconnect_script_path = os.path.join(SCRIPT_DIR, RECONNECT_SCRIPT_NAME)
+
+ # 记录开始时间
+ start_time = time.time()
+ # 调用外部重启脚本
+ result = subprocess.run(
+ [sys.executable, reconnect_script_path],
+ check=True,
+ capture_output=True,
+ text=True,
+ timeout=30
+ )
+ # 计算耗时
+ elapsed = time.time() - start_time
+
+ # 重置成功标记,设置重启状态
+ reconnect_success_detected = False
+ reconnect_in_progress = True
+ reconnect_start_time = time.time()
+ reconnect_attempts += 1
+ reconnect_count += 1
+
+ logging.info(f"【重启尝试 {reconnect_attempts}/{max_reconnect_attempts}】执行成功,耗时:{elapsed:.2f}s,总重启次数:{reconnect_count}")
+ return True
+ except subprocess.CalledProcessError as e:
+ logging.error(f"【重启失败】错误代码:{e.returncode}\nstdout: {e.stdout.strip()}\nstderr: {e.stderr.strip()}")
+ except FileNotFoundError:
+ logging.error(f"【重启失败】未找到重启脚本:{reconnect_script_path}")
+ except subprocess.TimeoutExpired:
+ logging.error(f"【重启失败】执行超时(超过30秒)")
+ except Exception as e:
+ logging.error(f"【重启异常】未知错误:{str(e)}", exc_info=True)
+
+ reconnect_attempts += 1
+ logging.warning(f"【重启尝试 {reconnect_attempts}/{max_reconnect_attempts}】失败")
+ return False
+
+def process_log_line(line):
+ """处理日志行并检查是否需要重启及重启是否成功"""
+ global last_position, processed_times, reconnect_in_progress, reconnect_success_detected, reconnect_attempts
+
+ # 检查是否是重启成功的标志日志
+ if reconnect_in_progress and 'Warning' in line and '[AxMsRdpClient09Host.cs(ReConn:42)]' in line and 'RDP Host: Call ReConn' in line:
+ logging.info(f"【重启成功验证】检测到成功标志: {line}")
+ reconnect_success_detected = True
+ reconnect_in_progress = False
+ reconnect_attempts = 0 # 重置尝试次数
+ return True
+
+ # 原有逻辑:检查是否需要重启
+ if 'Warning' in line:
+ if 'OnRdpClientDisconnected' in line and not reconnect_in_progress:
+ logging.warning(f"【触发重启】{line}")
+ return execute_reconnect()
+ elif 'ReConn:42' in line:
+ logging.info(f"【忽略信号】{line}")
+ else:
+ logging.info(f"【未知警告】{line}")
+
+ # 时间戳处理
+ try:
+ if '[' in line and ']' in line:
+ timestamp_str = line.split(']')[0][1:]
+ log_time = datetime.strptime(timestamp_str, "%H:%M:%S.%f").time()
+
+ time_key = timestamp_str.replace(':', '').replace('.', '')
+ if time_key not in processed_times:
+ processed_times[time_key] = True
+ logging.info(f"【新警告记录】{line}")
+ except ValueError:
+ logging.error(f"【无效时间戳】{line}")
+
+ return False
+
+def monitor_log_file(log_file):
+ """监控指定的日志文件"""
+ global last_position, processed_times, last_processed_date
+
+ try:
+ # 检查是否为新的一天
+ current_date = datetime.now().date()
+ if current_date != last_processed_date:
+ processed_times.clear()
+ last_processed_date = current_date
+ logging.info(f"【新的一天】开始监控{current_date}的日志文件")
+
+ # 获取文件大小
+ file_size = os.path.getsize(log_file)
+
+ # 从上次结束位置读取新内容
+ with open(log_file, 'r', encoding=ENCODING) as f:
+ if file_size < last_position:
+ logging.warning("【文件被截断或重置】重新从头开始读取")
+ f.seek(0)
+ else:
+ f.seek(last_position)
+ new_lines = f.read().splitlines()
+
+ # 处理新增内容
+ for line in new_lines:
+ process_log_line(line)
+
+ # 更新最后读取位置
+ last_position = file_size
+
+ except Exception as e:
+ logging.error(f"【监控异常】{str(e)}", exc_info=True)
+
+class LogFileHandler(FileSystemEventHandler):
+ """处理日志文件变化事件"""
+ def __init__(self, log_dir):
+ self.log_dir = log_dir
+
+ def on_modified(self, event):
+ global current_log_file
+
+ if not event.is_directory:
+ # 检查是否是当天日志文件
+ today_file = get_today_log_file(self.log_dir)
+ if today_file and event.src_path == today_file:
+ monitor_log_file(today_file)
+
+def start_monitoring(log_dir):
+ """启动日志监控(静默等待日志文件生成)"""
+ global current_log_file, last_position, reconnect_in_progress, reconnect_start_time, reconnect_success_detected, reconnect_attempts
+
+ # 验证监控目录是否有效(仅在启动时检查一次)
+ if not os.path.isdir(log_dir):
+ logging.error(f"【错误】监控目录不存在或无效: {log_dir}")
+ return False
+
+ try:
+ while True: # 外层循环:处理跨天切换
+ # 静默等待当天日志文件生成(每5秒检查一次)
+ while True:
+ current_log_file = get_today_log_file(log_dir)
+ if current_log_file:
+ logging.info(f"【找到日志文件】开始监控: {current_log_file}")
+ last_position = os.path.getsize(current_log_file) # 初始化读取位置
+ break
+ # 无日志文件时不输出错误,仅静默等待
+ time.sleep(5)
+
+ # 创建事件处理器和观察器
+ event_handler = LogFileHandler(log_dir)
+ observer = Observer()
+ observer.schedule(event_handler, path=log_dir, recursive=False)
+ observer.start()
+
+ # 监控循环:每1秒检查一次是否跨天或重启超时
+ try:
+ while True:
+ # 检查重启超时
+ if reconnect_in_progress:
+ elapsed_time = time.time() - reconnect_start_time
+ if elapsed_time > 20: # 超过20秒
+ if not reconnect_success_detected:
+ logging.warning(f"【重启验证超时】20秒内未检测到成功标志,尝试重新启动")
+ # 停止当前监控,准备重试
+ observer.stop()
+ observer.join()
+
+ # 如果未达到最大尝试次数,重新执行重启
+ if reconnect_attempts < max_reconnect_attempts:
+ execute_reconnect()
+ else:
+ # 达到最大尝试次数,重置状态
+ reconnect_in_progress = False
+ reconnect_attempts = 0
+
+ # 重新启动监控
+ event_handler = LogFileHandler(log_dir)
+ observer = Observer()
+ observer.schedule(event_handler, path=log_dir, recursive=False)
+ observer.start()
+ else:
+ # 已检测到成功标志,重置状态
+ reconnect_in_progress = False
+
+ # 检查是否跨天
+ today_file = get_today_log_file(log_dir)
+ if today_file != current_log_file:
+ # 跨天:停止当前监控,进入外层循环等待新文件
+ observer.stop()
+ observer.join()
+ logging.info(f"【跨天切换】当前日志文件已过期,等待新日志文件...")
+ break
+
+ time.sleep(1) # 缩短检查间隔为1秒,提高响应速度
+ except KeyboardInterrupt:
+ observer.stop()
+ observer.join()
+ return True
+ observer.join()
+ except Exception as e:
+ logging.error(f"【监控异常】{str(e)}", exc_info=True)
+ return False
+
+if __name__ == "__main__":
+ print("="*50)
+ print("日志监控程序")
+ print("作者:火山")
+ print("="*50)
+
+ # 尝试加载配置
+ log_watch_dir = load_config()
+
+ if not log_watch_dir:
+ log_watch_dir = configure_log_directory()
+ if not save_config(log_watch_dir):
+ print("配置保存失败,程序退出")
+ sys.exit(1)
+
+ print("="*50)
+ print(f"监控目录: {log_watch_dir}")
+ # 修改状态提示文本,更准确反映程序状态
+ print("正在监控中(等待当天日志文件生成)...")
+
+ try:
+ start_monitoring(log_watch_dir)
+ print("监控已成功启动")
+ print("作者:火山")
+ except Exception as e:
+ logging.error(f"【启动失败】{str(e)}", exc_info=True)
+ print(f"监控启动失败: {str(e)}")
print("请检查错误日志: 监控异常.txt")
\ No newline at end of file