From ab05b858e1a353839382c2eac633feb6eda6d027 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:35:35 +0800 Subject: [PATCH] Fix Build 1 --- .github/workflows/multi-platform-build.yml | 17 +- unilabos/app/main.py | 20 ++- unilabos/utils/README_LOGGING.md | 187 --------------------- unilabos/utils/environment_check.py | 1 + 4 files changed, 32 insertions(+), 193 deletions(-) delete mode 100644 unilabos/utils/README_LOGGING.md diff --git a/.github/workflows/multi-platform-build.yml b/.github/workflows/multi-platform-build.yml index bcba6db..719d460 100644 --- a/.github/workflows/multi-platform-build.yml +++ b/.github/workflows/multi-platform-build.yml @@ -1,11 +1,16 @@ name: Multi-Platform Conda Build on: + # 在 CI Check 工作流完成后触发(仅限 main/dev 分支) + workflow_run: + workflows: ["CI Check"] + types: + - completed + branches: [main, dev] + # 支持 tag 推送(不依赖 CI Check) push: - branches: [main, dev] tags: ['v*'] - pull_request: - branches: [main, dev] + # 手动触发 workflow_dispatch: inputs: platforms: @@ -20,6 +25,10 @@ on: jobs: build: + # 只有当不是 workflow_run 触发,或者 CI Check 成功时才执行 + if: >- + github.event_name != 'workflow_run' || + github.event.workflow_run.conclusion == 'success' strategy: fail-fast: false matrix: @@ -46,6 +55,8 @@ jobs: steps: - uses: actions/checkout@v4 with: + # 如果是 workflow_run 触发,使用触发 CI Check 的 commit + ref: ${{ github.event.workflow_run.head_sha || github.ref }} fetch-depth: 0 - name: Check if platform should be built diff --git a/unilabos/app/main.py b/unilabos/app/main.py index 063bf7a..2dedc55 100644 --- a/unilabos/app/main.py +++ b/unilabos/app/main.py @@ -1,6 +1,7 @@ import argparse import asyncio import os +import shutil import signal import sys import threading @@ -215,7 +216,8 @@ def main(): args_dict = vars(args) # 环境检查 - 检查并自动安装必需的包 (可选) - if not args_dict.get("skip_env_check", False): + skip_env_check = args_dict.get("skip_env_check", False) + if not skip_env_check: from unilabos.utils.environment_check import check_environment if not check_environment(auto_install=True): @@ -226,7 +228,19 @@ def main(): # 加载配置文件,优先加载config,然后从env读取 config_path = args_dict.get("config") - if os.getcwd().endswith("unilabos_data"): + + # 当 skip_env_check 时,默认使用当前目录作为 working_dir + if skip_env_check and not args_dict.get("working_dir") and not config_path: + working_dir = os.path.abspath(os.getcwd()) + print_status(f"跳过环境检查模式:使用当前目录作为工作目录 {working_dir}", "info") + # 检查当前目录是否有 local_config.py + local_config_in_cwd = os.path.join(working_dir, "local_config.py") + if os.path.exists(local_config_in_cwd): + config_path = local_config_in_cwd + print_status(f"发现本地配置文件: {config_path}", "info") + else: + print_status(f"未指定config路径,可通过 --config 传入 local_config.py 文件路径", "info") + elif os.getcwd().endswith("unilabos_data"): working_dir = os.path.abspath(os.getcwd()) else: working_dir = os.path.abspath(os.path.join(os.getcwd(), "unilabos_data")) @@ -245,7 +259,7 @@ def main(): working_dir = os.path.dirname(config_path) elif os.path.exists(working_dir) and os.path.exists(os.path.join(working_dir, "local_config.py")): config_path = os.path.join(working_dir, "local_config.py") - elif not config_path and ( + elif not skip_env_check and not config_path and ( not os.path.exists(working_dir) or not os.path.exists(os.path.join(working_dir, "local_config.py")) ): print_status(f"未指定config路径,可通过 --config 传入 local_config.py 文件路径", "info") diff --git a/unilabos/utils/README_LOGGING.md b/unilabos/utils/README_LOGGING.md deleted file mode 100644 index 9cb551b..0000000 --- a/unilabos/utils/README_LOGGING.md +++ /dev/null @@ -1,187 +0,0 @@ -# UniLabOS 日志配置说明 - -> **文件位置**: `unilabos/utils/log.py` -> **最后更新**: 2026-01-11 -> **维护者**: Uni-Lab-OS 开发团队 - -本文档说明 UniLabOS 日志系统中对第三方库和内部模块的日志级别配置,避免控制台被过多的 DEBUG 日志淹没。 - ---- - -## 📋 已屏蔽的日志 - -以下库/模块的日志已被设置为 **WARNING** 或 **INFO** 级别,不再显示 DEBUG 日志: - -### 1. pymodbus(Modbus 通信库) - -**配置位置**: `log.py` 第196-200行 - -```python -# pymodbus 库的日志太详细,设置为 WARNING -logging.getLogger('pymodbus').setLevel(logging.WARNING) -logging.getLogger('pymodbus.logging').setLevel(logging.WARNING) -logging.getLogger('pymodbus.logging.base').setLevel(logging.WARNING) -logging.getLogger('pymodbus.logging.decoders').setLevel(logging.WARNING) -``` - -**屏蔽原因**: -- pymodbus 在 DEBUG 级别会输出每一次 Modbus 通信的详细信息 -- 包括 `Processing: 0x5 0x1e 0x0 0x0...` 等原始数据 -- 包括 `decoded PDU function_code(3 sub -1) -> ReadHoldingRegistersResponse(...)` 等解码信息 -- 这些信息对日常使用价值不大,但会快速刷屏 - -**典型被屏蔽的日志**: -``` -[DEBUG] Processing: 0x5 0x1e 0x0 0x0 0x0 0x7 0x1 0x3 0x4 0x0 0x0 0x0 0x0 [handleFrame:72] [pymodbus.logging.base] -[DEBUG] decoded PDU function_code(3 sub -1) -> ReadHoldingRegistersResponse(...) [decode:79] [pymodbus.logging.decoders] -``` - ---- - -### 2. websockets(WebSocket 库) - -**配置位置**: `log.py` 第202-205行 - -```python -# websockets 库的日志输出较多,设置为 WARNING -logging.getLogger('websockets').setLevel(logging.WARNING) -logging.getLogger('websockets.client').setLevel(logging.WARNING) -logging.getLogger('websockets.server').setLevel(logging.WARNING) -``` - -**屏蔽原因**: -- WebSocket 连接、断开、心跳等信息在 DEBUG 级别会频繁输出 -- 对于长时间运行的服务,这些日志意义不大 - ---- - -### 3. ROS Host Node(设备状态更新) - -**配置位置**: `log.py` 第207-208行 - -```python -# ROS 节点的状态更新日志过于频繁,设置为 INFO -logging.getLogger('unilabos.ros.nodes.presets.host_node').setLevel(logging.INFO) -``` - -**屏蔽原因**: -- 设备状态更新(如手套箱压力)每隔几秒就会更新一次 -- DEBUG 日志会记录每一次状态变化,导致日志刷屏 -- 这些频繁的状态更新对调试价值不大 - -**典型被屏蔽的日志**: -``` -[DEBUG] [/devices/host_node] Status updated: BatteryStation.data_glove_box_pressure = 4.229457855224609 [property_callback:666] [unilabos.ros.nodes.presets.host_node] -``` - ---- - -### 4. asyncio 和 urllib3 - -**配置位置**: `log.py` 第224-225行 - -```python -logging.getLogger("asyncio").setLevel(logging.INFO) -logging.getLogger("urllib3").setLevel(logging.INFO) -``` - -**屏蔽原因**: -- asyncio: 异步 IO 的内部调试信息 -- urllib3: HTTP 请求库的连接池、重试等详细信息 - ---- - -## 🔧 如何临时启用这些日志(调试用) - -### 方法1: 修改 log.py(永久启用) - -在 `log.py` 的 `configure_logger()` 函数中,将对应库的日志级别改为 `logging.DEBUG`: - -```python -# 临时启用 pymodbus 的 DEBUG 日志 -logging.getLogger('pymodbus').setLevel(logging.DEBUG) -logging.getLogger('pymodbus.logging').setLevel(logging.DEBUG) -logging.getLogger('pymodbus.logging.base').setLevel(logging.DEBUG) -logging.getLogger('pymodbus.logging.decoders').setLevel(logging.DEBUG) -``` - -### 方法2: 在代码中临时启用(单次调试) - -在需要调试的代码文件中添加: - -```python -import logging - -# 临时启用 pymodbus DEBUG 日志 -logging.getLogger('pymodbus').setLevel(logging.DEBUG) - -# 你的 Modbus 调试代码 -... - -# 调试完成后恢复 -logging.getLogger('pymodbus').setLevel(logging.WARNING) -``` - -### 方法3: 使用环境变量或配置文件(推荐) - -未来可以考虑在启动参数中添加 `--debug-modbus` 等选项来动态控制。 - ---- - -## 📊 日志级别说明 - -| 级别 | 数值 | 用途 | 是否显示 | -|------|------|------|---------| -| TRACE | 5 | 最详细的跟踪信息 | ✅ | -| DEBUG | 10 | 调试信息 | ✅ | -| INFO | 20 | 一般信息 | ✅ | -| WARNING | 30 | 警告信息 | ✅ | -| ERROR | 40 | 错误信息 | ✅ | -| CRITICAL | 50 | 严重错误 | ✅ | - -**当前配置**: -- UniLabOS 自身代码: DEBUG 及以上全部显示 -- pymodbus/websockets: **WARNING** 及以上显示(屏蔽 DEBUG/INFO) -- ROS host_node: **INFO** 及以上显示(屏蔽 DEBUG) - ---- - -## ⚠️ 重要提示 - -### 修改生效时间 -- 修改 `log.py` 后需要 **重启 unilab 服务** 才能生效 -- 不需要重新安装或重新编译 - -### 调试 Modbus 通信问题 -如果需要调试 Modbus 通信故障,应该: -1. 临时启用 pymodbus DEBUG 日志(方法2) -2. 复现问题 -3. 查看详细的通信日志 -4. 调试完成后记得恢复 WARNING 级别 - -### 调试设备状态问题 -如果需要调试设备状态更新问题: -```python -logging.getLogger('unilabos.ros.nodes.presets.host_node').setLevel(logging.DEBUG) -``` - ---- - -## 📝 维护记录 - -| 日期 | 修改内容 | 操作人 | -|------|---------|--------| -| 2026-01-11 | 初始创建,添加 pymodbus、websockets、ROS host_node 屏蔽 | - | -| 2026-01-07 | 添加 pymodbus 和 websockets 屏蔽(log-0107.py) | - | - ---- - -## 🔗 相关文件 - -- `log.py` - 日志配置主文件 -- `unilabos/devices/workstation/coin_cell_assembly/` - 使用 Modbus 的扣电工作站代码 -- `unilabos/ros/nodes/presets/host_node.py` - ROS 主机节点代码 - ---- - -**维护提示**: 如果添加了新的第三方库或发现新的日志刷屏问题,请在此文档中记录并更新 `log.py` 配置。 diff --git a/unilabos/utils/environment_check.py b/unilabos/utils/environment_check.py index 3963b9e..73c0b10 100644 --- a/unilabos/utils/environment_check.py +++ b/unilabos/utils/environment_check.py @@ -24,6 +24,7 @@ class EnvironmentChecker: "msgcenterpy": "msgcenterpy", "opentrons_shared_data": "opentrons_shared_data", "typing_extensions": "typing_extensions", + "crcmod": "crcmod-plus", } # 特殊安装包(需要特殊处理的包)