Metadata-Version: 2.4
Name: fourier-resm
Version: 1.5.1
Summary: 远程主机资源监控工具：SSH 采集 CPU / 内存 / 网络 / 磁盘 / 温度 + 持续 ping，支持 Web 实时面板与日志回放
Author: Fourier
License: MIT
Project-URL: Homepage, https://gitlab.fftaicorp.com/pfs/resource_monitor
Project-URL: Source, https://gitlab.fftaicorp.com/pfs/resource_monitor
Keywords: monitoring,ssh,ping,resource,system,flask,dashboard
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: System Administrators
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Monitoring
Classifier: Topic :: System :: Networking :: Monitoring
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: paramiko>=3.0.0
Requires-Dist: flask>=3.0.0
Dynamic: license-file

# fourier-resm · 远程主机监控工具

[![PyPI version](https://img.shields.io/pypi/v/fourier-resm.svg)](https://pypi.org/project/fourier-resm/)
[![Python versions](https://img.shields.io/pypi/pyversions/fourier-resm.svg)](https://pypi.org/project/fourier-resm/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)

持续 ping 目标 IP 并通过 SSH 采集目标机器的系统资源（CPU / 内存 / Swap / 网络 / 磁盘 IO / CPU 温度 / loadavg），实时写入 CSV 日志，并附带 Web 实时面板与日志回放。

PyPI: <https://pypi.org/project/fourier-resm/>

## 安装

```bash
pip install fourier-resm
```

## 快速开始

```bash
fourier-resm <user> <host>
```

默认会：交互式提示输入 SSH 密码 → 启动 Web 面板于 <http://0.0.0.0:8000/>。

示例：
```bash
fourier-resm root 192.168.1.100
fourier-resm ubuntu 10.0.0.5 --ping-interval 0.5 --res-interval 1 -o ./logs
fourier-resm root 192.168.1.100 -k ~/.ssh/id_rsa --no-ask-pass    # 用密钥
fourier-resm root 192.168.1.100 --no-web                          # 仅 CLI
fourier-resm --replay-only ./logs                                 # 只读回放目录
fourier-resm --replay-only ./logs/ping_1.2.3.4_20260423_120000.csv # 只读回放单会话
```

## 功能

- **Ping**：默认 1s 一次（可调 0.05 ~ 60s），延迟精度 0.001 ms。
- **SSH 资源采集**（远端 / PC1）：通过远端 `/proc/*` 计算 1 秒区间的 CPU / 网络 / 磁盘速率：
  - `cpu_percent`
  - `mem_total/used/avail_MB`、`mem_percent`
  - `swap_total/used_MB`、`swap_percent`
  - `net_rx/tx`（Mbps 与 MB/s 双单位）
  - `disk_read/write`（MB/s）
  - `cpu_temp_C`（优先 coretemp/k10temp/thermal_zone）
  - `loadavg`（1/5/15 分钟）
  - 每块网卡的 rx/tx 速率
  - **UDP 错误计数**（`udp_in_errors`/`rcvbuf_errors`/`sndbuf_errors`，1 秒窗口内的增量；用于排查 LiveKit/Zenoh 丢包）
  - **socket 数量**（`tcp_sockets`/`udp_sockets`，从 `/proc/net/tcp{,6}` 计数）
  - **`/dev/shm` 用量**（`shm_used_MB`/`shm_files`，dora 共享内存泄漏检测）
  - **`tracked_procs`**：按正则 `RESM_PROC_PATTERN` 过滤的关键长跑进程列表，每条含 `pid/name/cmd/rss_MB/threads/fds`，按 RSS 倒序取前 40 条。默认正则覆盖 `dora|livekit|video_publisher|fourier-record|teleop|...`，**用于一小时左右才出现的 RSS / fd 泄漏排查**。
- **本地资源采集（PC3 / 控制端，自动启用）**：与远端**完全相同**的 schema，由 `_sampler.sample()` 在本进程内直接调用，写入 `local_<本机hostname>_<时间戳>.csv`。
- **实时写盘**：每条记录立即 flush 到 CSV。
- **Web 面板**：6 个 KPI + 6 张 Chart.js 实时图，支持「最近 N 分钟」窗口、运行时调节采样频率。
- **日志回放**：列出历史会话，双端点时间滑块 + 播放头，全部图表同步回放，支持变速；本地 `local_*.csv` 与远端 `resource_*.csv` 在 session 列表中各占一条（host 字段不同）。
- **断线自动重连**：SSH 断开后指数退避重连；ping 与本地采集线程独立不受影响。

## 输出文件

每次启动在 `-o` 指定目录（默认 `~/logs/<远端host>_MMDD_logs/`）下生成三个 CSV：

| 文件名 | 内容 |
|---|---|
| `ping_<远端IP>_<ts>.csv`     | 网络延迟 / 丢包 |
| `resource_<远端IP>_<ts>.csv` | **PC1**（远端）通过 SSH 采集的资源指标 |
| `local_<本机hostname>_<ts>.csv` | **PC3**（运行 fourier-resm 的本机）资源指标，schema 与 resource 完全一致 |

> v1.3 起 `resource_*.csv` 与 `local_*.csv` 的列从 19 扩到 27 列；旧日志（19 列）仍可通过新版回放正常加载，新增列在旧日志中显示为空。

## Console 侧 与 NUC 侧 采集信息对照表

> Console 侧 = 运行 `fourier-resm` 的本机（PC3 / 控制端）
> NUC 侧 = 通过 SSH 连接的远端目标机（PC1 / 机器人 NUC）

### 持续采集（`local_*.csv` / `resource_*.csv`，27 列 schema 完全一致）

由 `_sampler.sample()` 实现：Console 侧在本进程直接调用；NUC 侧把 `_sampler.py` 源码作为 SSH heredoc 喂给远端 `python3`，远端只读 `/proc` 和 `/sys`，**不在 NUC 写盘**，stdout 一行 `key=value|...` 回传。

| 类别 | 字段 | 说明 |
|---|---|---|
| **CPU** | `cpu_percent` | 1 秒内整机 CPU 占用率（基于 `/proc/stat` 增量） |
|        | `cpu_temp_C` / `cpu_temps_detail` | CPU 最高温度 + 各传感器读数（coretemp/k10temp/thermal_zone） |
|        | `loadavg_1_5_15` | 1/5/15 分钟系统负载 |
| **内存** | `mem_total/used/avail_MB`、`mem_percent` | `/proc/meminfo` |
|         | `swap_total/used_MB`、`swap_percent` | Swap 占用 |
| **网络** | `net_rx/tx (Mbps)` / `(MB/s)` | 全网卡总速率（双单位） |
|         | `per_interface(Mbps)` | 每块网卡 rx/tx（不含 lo） |
|         | `udp_in_errors` / `rcvbuf_errors` / `sndbuf_errors` | 1 秒窗口内 UDP 错误增量（LiveKit/Zenoh 丢包排查） |
|         | `tcp_sockets` / `udp_sockets` | `/proc/net/{tcp,tcp6,udp,udp6}` 行数 |
| **磁盘** | `disk_read/write (MB/s)` | 全磁盘总速率（不含 loop/ram） |
| **共享内存** | `shm_used_MB` / `shm_files` | `/dev/shm` 用量与文件数（dora 共享内存泄漏） |
| **关键进程** | `tracked_procs` | 正则 `RESM_PROC_PATTERN` 匹配的进程，按 RSS 倒序前 40 条，每条含 `pid/name/cmd/rss_MB/threads/fds` |
|             | `top_procs` | `ps ax --sort=-%cpu` 前 30 行 |

> Ping (`ping_*.csv`) 仅 Console 侧采集（用本机 `ping` 命令打 NUC，记录 `timestamp, host, latency(ms), status`），每 5 秒终端打印 min/avg/max。

### 冻结快照（`freeze-console-*.tar.gz` / `freeze-nuc-*.tar.gz`，点按钮一次抓一份）

两侧脚本结构相同，差异在于针对各自角色的额外信息：

| 收集项 | Console (`capture-freeze-console.sh`) | NUC (`capture-freeze-nuc.sh`) | 备注 |
|---|---|---|---|
| 容器 `docker logs --since 10m` | ✅ | ✅ | `docker-logs.txt` |
| `livekit-events.txt`（grep `lk-evt`） | ✅ | ✅ | |
| `errors.txt` 关键词 | `error\|exception\|traceback\|disconnect\|reconnect\|timeout\|fail\|token\|401\|403` | `error\|exception\|traceback\|disconnect\|reconnect\|timeout\|fail` | Console 多了鉴权类 |
| `docker stats --no-stream` | ✅ | ✅ | |
| 容器内 `ps -eLf` | ✅ | ✅ | |
| 关键进程 fd / RSS / threads | `command_publisher\|nuc_data_subscriber\|qnexo\|exo_driver\|dora-guardian` | `video_publisher\|dora-depthai\|fourier-record\|teleop-node\|joint_publisher\|command_subscriber\|nuc-data` | |
| `ss -tinoe state established` | ✅ | ✅ | TCP |
| `ss` :443 / UDP / `ip route` | ✅ | ✅ | |
| `ping -c 10` 到 NUC | ✅ | — | Console 主动测远端 |
| `mtr -rn -c 10`（若装了） | ✅ | — | |
| `dig` DNS | ✅（`fftaicorp.com`） | — | NUC 只收 `resolv.conf` |
| `resolv.conf` | — | ✅ | |
| `system.txt`：uptime/load/`free -m`/`df -h`/`sensors`/`dmesg` | ✅ | ✅ | |
| `iostat -x 1 3` | — | ✅ | NUC 排查磁盘瓶颈 |
| 每核 cpufreq `scaling_cur_freq` | — | ✅ | NUC 排查热降频 |
| `lsusb` + OAK 检测 (`usb.txt`) | — | ✅ | NUC 接 OAK 摄像头 |
| `container-env.txt` env 过滤 | `livekit\|video\|fps\|downscale\|identity\|room` | `livekit\|video\|image\|fps\|hw_jpeg\|downscale\|identity\|room` | NUC 多了 `image\|hw_jpeg` |
| `severity.txt` | L0~L5（如有传 `--level`） | 同 | |
| `README.txt` 浏览器抓 DevTools / WebRTC 提示 | ✅ | — | 只有 Console 跑 UI |

> 所有文件最终都落到 Console 侧的 `-o` 目录（默认 `~/logs/<host>_MMDD_logs/`）。NUC 侧脚本在 `/tmp` 临时打包，SFTP 拉回后远端文件**全部清理**（脚本自删 + Console 端再做一次防御性 `rm`）。

### 容器名 — 两侧均假设跑在 Docker 容器里，但**容器名不固定**

冻结快照脚本核心是 `docker exec <container> ...`，因此**仅这部分**需要容器（持续采集只读 `/proc`、`/sys`，与是否容器化无关）。

两侧均**自动探测**：遍历本机 `docker ps`，逐个 `docker exec <c> pgrep -af <pattern>`，第一个命中下列进程的容器即被认定：

| 端 | 自动探测的进程模式 |
|---|---|
| Console | `command_publisher \| nuc_data_subscriber \| qnexo \| exo_driver` |
| NUC     | `video_publisher \| dora-depthai \| fourier-record \| joint_publisher \| command_subscriber` |

容器叫什么名字都行（`dora-rt`、`nuc-app`、`teleop-console-1` …），只要里面跑上述任一进程即可。探测失败时脚本会列出所有 `docker ps` 让你手动指定；Web UI 的「📸 抓取冻结快照」对话框里也有「NUC 容器」/「Console 容器」输入框，留空即自动探测。

> 若有"宿主机直接跑（非容器）"场景，目前脚本会失败 —— 没有 `--no-docker` 模式。

## 自定义关键进程过滤

在**目标机器**上设环境变量 `RESM_PROC_PATTERN`（区分大小写不敏感的正则）即可改变 `tracked_procs` 的匹配集合：

```bash
# 远端 PC1
ssh root@pc1 RESM_PROC_PATTERN='video_publisher|fourier-record' systemctl restart ...
# 本机 PC3
RESM_PROC_PATTERN='livekit|teleop|console' fourier-resm root <PC1_IP>
```

## 参数

| 参数 | 说明 | 默认 |
| --- | --- | --- |
| `user` | SSH 用户名（位置参数） | 必填 |
| `host` | 目标 IP / 主机名（位置参数） | 必填 |
| `-P/--port` | SSH 端口 | 22 |
| `-k/--key` | SSH 私钥路径 | 无（尝试 ssh-agent / 默认密钥） |
| `-p/--password` | SSH 密码（不建议命令行传入） | 无 |
| `--no-ask-pass` | 禁用交互式密码输入 | 默认**开启**交互 |
| `--ping-interval` | Ping 间隔（秒） | 1.0 |
| `--res-interval` | 资源采样间隔（秒） | 2.0 |
| `-o/--output` | 日志目录 | `~/logs/<host>_MMDD_logs/` |
| `--replay-only PATH` | 只读回放模式：只读取历史日志目录或单个 CSV，会自动启用 Web，不进行采集与写盘 | 无 |
| `--no-web` | 禁用 Web 面板 | 默认**开启** Web |
| `--web-host` | Web 监听地址 | `0.0.0.0` |
| `--web-port` | Web 监听端口 | 8000 |

## 输出

在 `-o` 指定目录（默认 `~/logs/<host>_MMDD_logs/`）下生成：

- `ping_<host>_<时间戳>.csv`：`timestamp, host, latency(ms), status`
- `resource_<host>_<时间戳>.csv`：含 CPU / 内存 / Swap / 网络(Mbps & MB/s) / 磁盘 / CPU 温度 / loadavg / 每网卡速率

控制台每 5 秒打印一次 ping 丢包 / min/avg/max 汇总。

## 目标机器要求

- Linux，有 `python3`（或 `python`）；仅读取 `/proc/*` 与 `/sys/class/thermal|hwmon`。
- SSH 可连接。
- 若 ICMP 被禁用，ping 会全部超时，但 SSH 资源采集仍正常工作。

## 源码开发

```bash
git clone https://gitlab.fftaicorp.com/pfs/resource_monitor.git
cd resource_monitor
pip install -e .
fourier-resm <user> <host>
```

## License

MIT — 见 [LICENSE](./LICENSE)。
