- 桌面应用
- 指标监控
- 可观测性
【免费下载链接】stats
macOS system monitor in your menu bar
Stats 是一款运行在 macOS 菜单栏中的开源系统监视工具,能够实时展示 CPU、GPU、内存、磁盘、网络、电池、传感器与蓝牙等硬件指标。本文以官方 README.md 为骨架,结合仓库源码,系统讲解它的安装方式、功能模块、常见问题排查与源码级实现原理,帮助读者从"会用"进阶到"看懂"。
项目概览:一个菜单栏里的"系统监视器"
Stats 的核心定位是一句话:macOS system monitor in your menu bar(README.md)。它不提供传统意义上的独立主窗口界面,而是以菜单栏图标、点击后的弹出面板(popup)和可选桌面小组件(widgets)的形式呈现系统状态。
从 Stats/AppDelegate.swift 可以看到,应用启动时会实例化并挂载 10 个监视模块:
var modules: [Module] = [ CPU(), GPU(), RAM(), Disk(), Sensors(), Network(), Battery(), Bluetooth(), Clock(), Remote() ]每个模块对应一个独立的动态库目标(见 Modules/ 目录),在运行时由宿主 App 统一调度,这种"宿主 + 模块插件"的架构让各功能彼此隔离、可按需启停。README 列出的核心能力包括:
- CPU 利用率(含每核负载、能效核/性能核/超核集群分组)
- GPU 利用率
- 内存使用情况
- 磁盘利用率
- 网络使用情况(流量、速率、Wi-Fi 详情)
- 电池电量与健康度
- 风扇控制(遗留功能,不维护,见下文"风扇控制"小节)
- 传感器信息(温度 / 电压 / 功率)
- 蓝牙设备状态
- 多时区时钟
- 远程监视(Remote 模块,SSH/无头模式部署)
环境要求
README 明确了两条硬性前提(README.md):
- 支持macOS 12 (Monterey) 及更新版本;
- 不支持 macOS 测试版(Beta),仅支持稳定版本。
从源码看,Sensors模块使用 Objective-C 桥接读取 SMC(Apple 的电源/传感器管理控制器),SMC/目录下存在需要管理员权限安装的eu.exelban.Stats.SMC.Helper特权辅助程序;而 Apple Silicon 与 Intel 的读取路径也不同(如 Modules/CPU/main.swift 中#if arch(x86_64)分支:Intel 上读取 CPU 频率限制,Apple Silicon 上读取频率),因此请务必在受支持的稳定系统版本上使用。
安装方式详解
README 提供了四种安装途径(README.md),其中三种面向普通用户,一种面向远程/无头部署。
手动安装(Manual)
从 Releases 页面下载Stats.dmg,打开后将 App 拖入"应用程序"文件夹即可。这也是最直观的安装方式,适合大多数普通用户。
Homebrew 安装
打开终端执行:
brew install stats适合习惯用 Homebrew 管理 macOS 软件的开发者,卸载时也只需brew uninstall stats。
无头安装 / SSH 远程部署(Headless)
这是 Stats 最有特色的安装场景:通过 SSH 远程安装 Stats,并把它配置为远程监视代理。执行:
curl -fsSL https://cdn.mac-stats.com/install.sh | bash脚本会依次完成:安装 App → 启用 Remote 模块 → 打印带授权码的 URL,在任意设备上打开该 URL 并登录你的 System Stats 账号以授权这台机器。授权后,Stats 开始向你的账号持续上报指标,并注册为登录时自动启动、崩溃后自动重启的后台代理。
对应脚本就在仓库的 Kit/scripts/install.sh 中,其参数体系相当完整:
| 参数 | 作用 |
|---|---|
-v, --version TAG | 安装指定 release 标签(默认latest) |
-a, --app PATH | 指定Stats.app的目标位置(默认/Applications/Stats.app) |
-c, --control | 允许远程控制命令 |
-u, --update | 允许远程触发更新 |
-r, --reauth | 即使已有令牌也强制重新登录 |
-h, --help | 显示帮助 |
脚本内部会处理 Keychain 令牌(eu.exelban.Stats.remote)、注册eu.exelban.Statslaunchd agent 等细节。Remote 模块本身在 Modules/Remote/ 中实现,负责与 System Stats 云端同步机器列表、在线状态、CPU/内存指标快照(如RemoteSnapshot、RemoteCPUModule、RemoteRAMModule等数据结构,见 Modules/Remote/main.swift)。
需要特别注意的限制(README 原话):这台 Mac 必须存在活跃的用户会话(锁屏状态也可以)才能运行 App;在完全无头(无人登录)的机器上,Stats 会在下次登录时才启动。
卸载(Uninstall)
运行 App 自带的卸载脚本(需要管理员权限,因为要移除 SMC 特权辅助程序):
sh /Applications/Stats.app/Contents/Resources/Scripts/uninstall.sh脚本源码位于 Kit/scripts/uninstall.sh,其清理流程包括:退出 Stats →launchctl bootout卸载 launch agent → 卸载并删除 SMC Helper 的 LaunchDaemon 与特权工具 → 删除 App 本体 → 清理~/Library/Application Support/Stats数据与 Keychain 中的授权令牌。README 同时提示,旧版本(针对更老系统)可从 mac-stats.com 的下载页获取(README.md)。
功能模块与数据采集原理
Stats 的每个模块都由三类"视图"组成:菜单栏 widget(图标区)、popup(点击图标后的弹出面板)与可选的门户/桌面组件,而数据则统一由Reader(读取器)周期性采集。理解 Kit/module/reader.swift 中的Reader<T>基类,就理解了整个数据管线的骨架:
- 每个 Reader 持有独立的轮询周期
interval(默认 1 秒)与回调callbackHandler; - 初始化时通过
DB.shared.setup(T.self, "\(module)@\(readerName)")在本地 DB 中恢复上一次的采样值; - 模块启用时
startReaders()启动各 Reader,禁用时lock()+stop()暂停采集(见 Kit/module/module.swift); - 存在"可见性感知":只有 popup/预览打开时才需要的 Reader 会进入 sleep 以节省资源(Kit/module/module.swift)。
以 CPU 模块为例,Modules/CPU/main.swift 同时注册了 6 个 Reader:LoadReader(总负载与每核负载)、ProcessReader(进程列表)、TemperatureReader、FrequencyReader、LimitReader(Intel 专属)与AverageLoadReader(1/5/15 分钟平均负载)。采集结果会同步推给 popup、portal、通知、预览和菜单栏各 widget。
模块的"长相"由各自的config.plist决定。以 Modules/CPU/config.plist 为例,它声明了:
Name:模块名CPU;State:默认启用(true);Symbol/AlternativeSymbol:菜单栏使用的 SF Symbol(cpu.fill,回退cpu);Widgets:可用 widget 类型及其默认状态、预览值、颜色支持与显示顺序,CPU 模块按序支持label → mini → line_chart → bar_chart → pie_chart → tachometer;Settings.popup/notifications、Preview.available:是否支持弹出面板、通知与预览。
其他模块(如 Modules/Remote/config.plist)结构与之一致,只是默认状态、图标与 widget 集合不同(Remote 默认关闭,使用server.rack图标)。
内存模块的采集则直接调用 Mach 内核接口:host_statistics64(machHostPort, HOST_VM_INFO64, ...)获取active/inactive/speculative/wired/compressed等页统计,并结合vm.swapusage系统调用计算 swap 用量、通过kern.memorystatus_vm_pressure_level判断内存压力等级(normal / warning / critical),见 Modules/RAM/readers.swift。网络模块则借助SystemConfiguration(动态获取主接口)、CoreWLAN(Wi-Fi 协议/加密/信道)与CoreLocation(读取 Wi-Fi 名称所需的定位权限)来获取接口流量与 Wi-Fi 详情,见 Modules/Net/readers.swift。
常见问题排查(FAQ 精讲)
README 的 FAQ 部分集中回答了用户高频问题,以下逐一展开,并附源码佐证。
如何调整菜单栏图标的顺序?
菜单栏图标的排序由 macOS 决定,而非 Stats 本身——安装 Stats 后首次重启,图标顺序可能发生变化。在 macOS Mojave (10.14) 及以上系统,按以下步骤手动调整任意菜单栏图标顺序:
- 按住 ⌘(Command 键);
- 把图标拖到菜单栏中想要的位置;
- 松开 ⌘ 键。
Stats 图标没有出现在菜单栏
macOS 26 新增了一项隐私控制:系统设置 → 菜单栏(Menu Bar)。App 必须在此处被显式允许,才能在菜单栏显示项目。如果 Stats 正在运行、至少有一个模块处于活动状态且至少启用了一个 widget,但菜单栏完全看不到图标,几乎可以断定是这项设置导致的。
解决方法:打开系统设置 → 菜单栏,将Stats开关打开。
桌面小组件不显示数据
由于 App 与小组件通信所依赖的系统进程(chronod)存在高数据负载问题,Stats 侧默认关闭了与小组件的通信。需要用户在 Stats 设置中手动开启macOS widgets选项(README.md)。这与代码中systemWidgetsUpdatesState开关一一对应:只有开启该选项时,CPU 等模块的 reader 回调才会把数据写入SystemWidgetUpdates并同步给桌面组件(见 Modules/CPU/main.swift 与 Modules/CPU/main.swift)。
解决方法:打开Stats 设置,将macOS widgets开关打开。
Wi-Fi 网络名称显示为 Unknown
macOS 要求读取 Wi-Fi 名称时具备定位服务(Location Services)权限。如果 Stats 的定位权限被关闭,网络名称可能直接显示为Unknown,且不会弹出权限提示(README.md)。这正是网络模块在 Modules/Net/readers.swift 中通过isUsableSSID过滤掉空值与<redacted>的原因——系统在未授权时会将 SSID 替换为<redacted>。
解决方法:打开系统设置 → 隐私与安全性 → 定位服务,确认定位服务已开启,并将Stats开关打开,然后退出并重新打开 Stats。
如何降低 Stats 的能耗或 CPU 占用?
Stats 已尽可能追求高效,但周期性读取数据本身并不廉价,而且"每个模块都有自己的开销"。如果想降低能耗,最直接的办法是关闭部分模块。README 明确指出:开销最大的模块是 Sensors(传感器)和 Bluetooth(蓝牙),在某些情况下关闭它们可将 CPU 占用与功耗最多降低约 50%(README.md)。
这一说法与源码架构吻合:传感器模块需要反复读取 SMC 键值(温度/电压/功率),蓝牙模块需要轮询周边蓝牙设备状态,两者的轮询成本天然高于 CPU/内存这类基于内核快照的读取。值得强调的是,50% 是"在某些情况下"的收益,具体效果取决于机器型号与已启用模块数量。
风扇控制(Fan control)
风扇控制目前处于遗留(legacy)模式:不再接收任何更新与修复,也不提供支持。它没有被移除,只是因为它在旧款 Mac 上工作得尚可。项目作者欢迎通过 PR 帮助改进该功能,但自身没有时间和精力继续维护(README.md)。
传感器显示错误的 CPU/GPU 核心数
这是一个高频误解。README 的解释非常关键(README.md):
CPU/GPU 传感器本质上是 CPU/GPU 上的热区(thermal zone),与核心数量或具体核心没有任何关系。例如 CPU 通常分为能效核与性能核两个集群,每个集群包含多个温度传感器,Stats 只是把这些传感器展示出来。因此"CPU Efficient Core 1"并不代表某个能效核的温度,它只是能效核集群内的某一个温度传感器。
此外,每代新 SoC 都会改变传感器键(SMC keys),因此需要花时间确定哪个 SMC 值对应哪个传感器。作者也公开寻求帮助:如果你知道如何在 Apple Silicon 上精确匹配传感器,欢迎联系。
App 崩溃了怎么办?
按以下顺序排查(README.md):
- 确认已使用最新版本——大概率已有修复崩溃的版本发布;
- 若已是最新版本,查阅已存在的 issue;
- 只有当现有 issue 都无法解决你的问题时,才新建 issue。
为什么我的 issue 被直接关闭、没有任何回复?
大概率是因为重复的 issue,且该问题、报告或建议已有答案。请先用"已关闭的 issue"搜索获取答案。
隐私与网络请求:External API
Stats不收集任何遥测或分析数据。它的全部外部请求仅指向以下两个 API(README.md):
https://api.mac-stats.com—— 用于更新检查和获取公网 IP 地址;https://api.github.com—— 更新检查的后备(fallback)。
更新检查逻辑与源码中的Updater(github: "exelban/stats", url: "https://api.mac-stats.com/release/latest")对应(见 Stats/AppDelegate.swift),即优先走自有服务器,失败时回退到 GitHub API。公网 IP 的获取特意不用任何第三方服务,而是使用作者自己的服务器。
如果你介意这些请求,有两个选项:
- 提交一个 PR,让这些功能无需外部服务器即可工作;
- 用任何网络过滤工具屏蔽上述两个域名(例如你正在使用 Little Snitch 之类工具时很容易做到)。注意:屏蔽后将收不到更新提醒,且网络模块中看不到公网 IP。
开源贡献规范:"Open source, but not open contribution"
Stats 是一个开源但非开放贡献的项目,这一方针在 README 中写得很直白(README.md):
- 开源:完整源码以 MIT 协议发布,你可以自由阅读、学习、fork 并构建自己的版本;
- 非开放贡献:项目由单人开发维护,保持稳定与连贯性优先于接受每一个变更——审查外部代码、在不同 Mac 与 macOS 版本上测试、后续维护,往往比从零编写还费时。
因此:未经邀请的 Pull Request 通常不会被接受,且可能未经评审就被关闭。想改动或新增功能,请先开 issue 讨论。例外情况是翻译与语言修复(始终欢迎),以及已经为项目做出重大贡献、实现风格与项目一致的贡献者。
支持项目的最佳方式是:报告 bug、改进翻译、通过 issue 提出想法。
多语言支持
Stats 支持 30+ 种界面语言(README.md),包括简体中文、繁体中文、英语、波兰语、乌克兰语、俄语、土耳其语、韩语、德语、西班牙语、越南语、法语、意大利语、葡萄牙语(巴西/葡萄牙)、挪威语、日语、捷克语、匈牙利语、保加利亚语、罗马尼亚语、荷兰语、克罗地亚语、丹麦语、加泰罗尼亚语、印度尼西亚语、希伯来语、斯洛文尼亚语、希腊语、波斯语、斯洛伐克语、泰语、爱沙尼亚语、印地语、芬兰语、孟加拉语和泰米尔语。
所有语言包都存放在 Stats/Supporting Files/ 下以*.lproj/Localizable.strings形式组织的目录中(如 zh-Hans.lproj),翻译工作由社区成员贡献。如果你愿意,也可以帮助新增语言或改进现有翻译。
许可证
Stats 以 MIT License 协议发布(README.md),允许自由阅读、学习、fork 与二次开发。
- 桌面应用
- 指标监控
- 可观测性
【免费下载链接】stats
macOS system monitor in your menu bar
相关推荐
Conky 入门与源码级实践:轻量系统监视器的安装、配置与深度定制指南
Conky 入门与源码级实践:轻量系统监视器的安装、配置与深度定制指南 Conky 是一款面向 X 桌面环境设计的免费、轻量级系统监视器,能够在桌面上以文本、进
桌面应用系统监控GoCD制品元数据标准:SPDX与CycloneDX集成
GoCD制品元数据标准:SPDX与CycloneDX集成 制品元数据管理现状与挑战 在现代持续集成/持续部署(CI/CD)流程中,软件供应链安全已成为关键议题。
桌面应用NanoClaw macOS 菜单栏状态指示器(Menu Bar Status Indicator)安装与源码解析
NanoClaw macOS 菜单栏状态指示器(Menu Bar Status Indicator)安装与源码解析 本指南完整讲解 NanoClaw 官方技能
人工智能AI 应用AI AgentAgent 沙箱交互助手
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考