""" 系统与网卡指标(供仪表盘轮询)。下行/上行为全机网卡合计速率(估算)。 """ from __future__ import annotations import time from typing import Any, Optional import psutil _last_net_time: float = 0.0 _last_net: Optional[dict[str, tuple[int, int]]] = None # name -> (sent, recv) def _net_rates_mbps() -> tuple[Optional[float], Optional[float], dict[str, Any]]: """返回 (上行 Mbps, 下行 Mbps, 原始片段)。""" global _last_net_time, _last_net now = time.monotonic() per = psutil.net_io_counters(pernic=True) cur: dict[str, tuple[int, int]] = {k: (v.bytes_sent, v.bytes_recv) for k, v in per.items()} detail: dict[str, Any] = {} up_mbps = down_mbps = None if _last_net is not None and _last_net_time > 0: dt = now - _last_net_time if dt > 0.05: ds = dr = 0 for name, (sent, recv) in cur.items(): if name in _last_net: ps0, pr0 = _last_net[name] ds += max(0, sent - ps0) dr += max(0, recv - pr0) up_mbps = round((ds * 8) / dt / 1_000_000, 3) down_mbps = round((dr * 8) / dt / 1_000_000, 3) detail["delta_seconds"] = round(dt, 3) _last_net = cur _last_net_time = now for name, (sent, recv) in cur.items(): detail.setdefault("interfaces", {})[name] = { "bytes_sent": sent, "bytes_recv": recv, } return up_mbps, down_mbps, detail def snapshot() -> dict[str, Any]: try: psutil.cpu_percent(interval=None) cpu = psutil.cpu_percent(interval=0.15) except Exception: cpu = None try: vm = psutil.virtual_memory() mem = { "percent": vm.percent, "used": vm.used, "total": vm.total, "available": vm.available, } except Exception: mem = {} try: sm = psutil.swap_memory() swap = {"percent": sm.percent, "used": sm.used, "total": sm.total} except Exception: swap = {} disks = [] try: for part in psutil.disk_partitions(all=False): try: usage = psutil.disk_usage(part.mountpoint) disks.append( { "device": part.device, "mountpoint": part.mountpoint, "fstype": part.fstype, "percent": usage.percent, "free": usage.free, "total": usage.total, } ) except (PermissionError, OSError): continue except Exception: pass up_mbps, down_mbps, net_detail = _net_rates_mbps() boot = None try: boot = int(psutil.boot_time()) except Exception: pass ffmpeg_procs = [] try: for p in psutil.process_iter(["pid", "name", "memory_info"]): try: name = (p.info.get("name") or "").lower() if "ffmpeg" not in name: continue mi = p.info.get("memory_info") ffmpeg_procs.append( { "pid": p.info["pid"], "name": p.info.get("name"), "rss": mi.rss if mi else 0, } ) except (psutil.NoSuchProcess, psutil.AccessDenied): continue except Exception: pass return { "ts": time.time(), "cpu_percent": cpu, "cpu_count_logical": psutil.cpu_count(logical=True), "memory": mem, "swap": swap, "disks": disks, "network": { "up_mbps": up_mbps, "down_mbps": down_mbps, "detail": net_detail, }, "boot_time_unix": boot, "ffmpeg_processes": ffmpeg_procs[:24], }