RepoDaily · 2026-08-10 · Self-hosted app

witr:把进程、端口、容器或文件一路追溯回它的启动源头

#9 Self-hosted app Go +342 pranshuparmar/witr 打开仓库

一个用 Go 编写的 CLI 和 bubbletea TUI 工具,能重建进程、监听端口、容器或文件锁背后的因果链,并附带一个无需安装的浏览器演练场。

项目类型Self-hosted app
最适合需要排查神秘进程、端口占用、dpkg 锁或容器蔓延的 Linux 运维和开发者,希望在一个视图中看到完整的 systemd 祖先链
风险等级
评估时间浏览器演练场 10–15 分钟;用 Go 1.25+ 编译 CLI 不到 5 分钟

核心问题: 从 systemd init 一路追到目标进程的因果链视图,能否替代你当前组合使用 lsof、pstree 和 docker inspect 的习惯?

90/100

RepoDaily 采用评分

RepoDaily 将该项目的采用分评为 90/100(强):分数来自文章来源、安装路径、生产风险、差异化、许可证清晰度以及 AI/Agent 适配度。

基于 RepoDaily 来源和采用说明的方向性评分,不是基准测试。风险: 低
96证据质量

包含 4 个来源、覆盖 3 类来源;如有 RepoDaily 独有模块,会进一步提高证据分。

100可安装/可试用性

检测到 5 个工作流步骤、6 个下一步动作,以及 4 个命令/安装信号。

70维护可信度

趋势热度为 +342 stars;如内容中有 release、issue 或维护信号,会提高维护可信度。

100生产准备度

采纳风险标记为 low,并包含 4 条安全说明与 3 条跳过条件。

100差异化

3 个机会视角、5 个替代方案,以及 4 个类型化模块支撑差异化判断。

82许可证清晰度

文章中包含许可证来源或许可证表述。

60Agent / AI 适配度

文章正文和元数据中检测到 2 个 AI/Agent 相关信号。

项目概览

witr 是一个单一 Go 二进制程序,回答一个看似简单实则很难的问题:这个东西为什么在跑?给它一个 PID、端口、文件锁或容器 ID,它会沿着内核和 cgroup 元数据向上遍历 systemd 单元和父进程,最终打印出一条人类可读的因果链——通常终止于 PID 1 或某个已知的服务管理器。输出设计成可以直接粘贴到事故群和复盘文档里。

工具提供两种使用界面:基于 cobra 的 CLI 用于脚本和管道操作;不带参数运行 witr 时则打开 bubbletea TUI。TUI 包含进程、端口、容器和锁四个面板,配有祖先关系侧栏——形状上类似传统进程浏览器,但以因果链逻辑为核心,而非平铺的表格。

一个显著的差异化资产是演练场目录。docs/ 文件夹同时作为 GitHub Pages 站点直接部署,在浏览器中运行一个完全模拟的 Linux 机器。访客可以对编写的模拟数据输入真实的 witr 命令,不会触碰本机。它既是引导教程(webbox 和 devbox 两个事故场景),也是一个自由沙盒。

演练场的输出保真度在 CI 中强制保证。js/engine.js 是 witr 的 Go 输出层(internal/output/*.go 和 internal/app/app.go)的忠实移植,scripts/check-fixtures.mjs 使用固定时钟在相同模拟世界上重放 JS 引擎,并逐字节断言与 Go 输出包生成的黄金 fixture 完全一致。如果浏览器引擎与真实 CLI 产生偏差,构建会直接失败。

解决什么问题

  • 部署失败报 EADDRINUSE,你无法确定是哪个队友的 http.server 占用了 :8000——演练场的 webbox 场景精确模拟了这种情况。
  • dpkg 或 unattended-upgrade 持有锁,每次 apt 调用都被阻塞——witr 将锁文件追溯到持有进程及其 systemd 单元。
  • git index.lock 阻止所有提交,你需要判断它是残留的才能安全删除——devbox 场景通过 fix-by-kill 流程引导你完成。
  • 一个 python3 僵尸进程被孤立,你必须找到能回收它的父进程——witr 展示完整祖先关系,而不只是在表格中列出僵尸。
  • 一个游荡的 ffmpeg 占满 CPU,你需要完整的因果链来证明在生产环境中杀掉它是合理的。

工作原理

  1. 使用主标志指定目标:--pid 追踪进程,--port 追踪监听套接字,--file 追踪文件或锁,--container 追踪容器。
  2. witr 从 /proc 收集进程元数据,解析端口的套接字归属,并通过 coreos/go-systemd 和 godbus/dbus 读取 cgroup 和 systemd 单元数据。
  3. 沿父 PID 向上遍历,在每个节点标注其 systemd 单元、用户和容器信息(如适用),直到到达 PID 1 或服务管理器边界。
  4. CLI 默认渲染 ANSI 文本链;--json 输出机器可读格式,--tree 显示嵌套视图,--env 包含环境变量,--verbose 为每个节点添加更多细节。
  5. 不带参数运行时,bubbletea TUI 打开进程/端口/容器/锁面板和祖先关系侧栏,随导航实时更新。

命令界面

  • 入口点:./cmd/witr——编译后在仓库根目录生成名为 witr 的单一二进制文件。
  • 演练场教程中练习的核心追踪标志:--port、--file、--pid、--verbose。
  • 可选支线标志(在事故追踪器中勾选):--json、--tree、--env、--container。
  • 不带参数运行 witr 打开交互式 TUI:进程/端口/容器/锁面板加祖先关系侧栏,基于 bubbletea v1.3.10 构建。
  • 编译需要 Go 1.25+(go.mod 声明 toolchain go1.25.10);CONTRIBUTING.md 指定 `go build -o witr ./cmd/witr` 然后执行 `./witr --help` 作为冒烟测试。
  • -ldflags 块注入提交和日期元数据,使 `witr --version` 报告准确的构建信息。

零安装试用路径

docs/ 文件夹由 GitHub Pages 直接部署到 owner 的 witr Pages URL。它托管了一个终端优先的交互式演练场,模拟一台 Linux 机器,其中所有进程、端口、容器和锁数据都是预先编写的。

提供两个引导事故场景。webbox 上,任务是信息性的:部署因 :8000 的 EADDRINUSE 而失败(占用者是一个队友的 http.server),dpkg 锁由计划的 unattended-upgrade 持有,Node 应用的资源占用需要评估。devbox 上,任务是 fix-by-kill:git index.lock 阻止提交,python3 僵尸需要通过父进程回收,游荡的 ffmpeg 占满 CPU——kill 命令会真正移除进程及其子树,引擎、星座视图、TUI 和事故追踪器都会实时反映。

一个基于 three.js 的进程星座可视化整台机器。查询解析时,因果链(systemd → … → 目标)会高亮,其余节点变暗。节点和图例(pid 1 / 监听者 / 进程 / 警告)均可点击。

Reset 按钮恢复原始模拟环境。演练场也可以本地运行:`cd docs && python3 -m http.server 8099`,因为 ES 模块需要 http:// 而非 file://。

架构解读

  • 模块路径:github.com/pranshuparmar/witr,go.mod 声明 go 1.25 和 toolchain go1.25.10。
  • TUI 技术栈:charmbracelet/bubbles v1.0.0 提供组件,bubbletea v1.3.10 提供 Elm 架构运行时,lipgloss v1.1.0 负责样式。
  • CLI 框架:spf13/cobra v1.10.2 配合 spf13/pflag v1.0.10 进行标志解析。
  • 系统内省:coreos/go-systemd/v22 v22.7.0 读取单元和 cgroup 数据,godbus/dbus/v5 v5.1.0 通过 D-Bus 与服务管理器通信。
  • 终端支持:mattn/go-isatty v0.0.20 检测 TTY,muesli/reflow 处理文本换行,golang.org/x/sys v0.38.0 提供底层系统调用。
  • 输出层位于 internal/output/*.go,应用路由位于 internal/app/app.go——演练场的 js/engine.js 正是移植了这些包。
  • 黄金 fixture 由 fixtures/gen/ 中的小型 Go 程序通过 witr 实际输出包生成,确保测试 fixture 与真实 CLI 行为一致。

维护风险解读

项目尚处于早期,但展现了刻意的工程纪律。CI 中的保真度检查——scripts/check-fixtures.mjs 断言 JS 演练场引擎与 Go 生成的黄金 fixture 之间逐字节相等——意味着任何对 witr 输出格式的修改如果没有同步到演练场,都会导致构建失败。这有效防止了同时发布 CLI 和 Web 演示的项目中最常见的漂移问题。

所有依赖在 go.mod 中都锁定到具体版本,没有使用浮动标签或 replace 指令。Charm 技术栈(bubbletea、bubbles、lipgloss)和 systemd/dbus 库在上游都有活跃维护,降低了供应链停滞的风险。

CONTRIBUTING.md 记录了清晰的编译路径(Go 1.25+,`go build -o witr ./cmd/witr`),并引导贡献者通过 GitHub Issues 提交问题和增强建议,表明这是标准的开源贡献模式。

谁适合关注

适合关注

  • 在 tmux 中工作并将 CLI 输出粘贴到事故频道的 Linux 运维人员
  • 需要快速获取端口冲突或包管理器锁卡死等告警因果链的 SRE
  • 在本地 docker-compose 环境中调试多个容器端口冲突的开发者
  • 教授 Linux 进程概念的讲师——浏览器演练场是零风险沙盒,配有引导式事故场景

可以先跳过

  • 仅使用 Windows 或以 macOS 为主的用户:witr 的核心价值依赖 /proc、cgroups 和 systemd,TUI 可能能启动但谱系数据会不完整
  • 已经将流程追踪和关联内置到商业 APM 平台中的组织
  • 需要远程、跨主机关联的用户——witr 是单机设计,不在多台机器间聚合

风险与注意事项

Apache-2.0 的 Go 二进制程序加一个静态文件浏览器演练场;无后台服务、无网络调用、无持久化状态。

  • 许可证为宽松的 Apache 2.0,已在仓库根目录 LICENSE 文件中确认。
  • 编译使用标准命令 `go build -o witr ./cmd/witr`(Go 1.25+),无需 CGO 或 Go 工具链之外的运行时依赖。
  • 演练场是由 GitHub Pages 托管的静态文件;docs/README.md 明确说明它模拟 witr 操作编写好的 fixture 数据,不触碰访客机器。
  • 工具本质上是只读的——它追踪和展示元数据,不会执行杀死、修改或持久化操作(演练场中的 kill 命令也仅作用于模拟数据)。
  • 浏览器演练场完全在客户端运行,操作的是编写的 fixture 数据;docs/README.md 声明它模拟 witr 而非真实 shell,不触碰访客机器。
  • CLI 读取 /proc、cgroup 和套接字元数据;预计需要与 ps 或 lsof 相同的权限才能查看其他用户的进程。
  • go.mod 锁定了所有依赖版本:bubbletea v1.3.10、cobra v1.10.2、go-systemd/v22 v22.7.0、dbus/v5 v5.1.0——无浮动标签或 replace 指令。
  • 源码包中未引用遥测端点或回传行为;演练场中的 analytics.js 被描述为可选的 GoatCounter 封装,被拦截时自动 no-op。

替代方案比较

方案适用场景代价
htop
你需要一个实时交互式平铺进程查看器,支持排序和过滤,但不需要从端口或锁追溯到 systemd init 的因果谱系。免费,GPL,许多发行版预装
btop
你想要视觉丰富的系统监控器,有 CPU、内存、磁盘和网络图表,但同样受限于平铺进程视图。免费,Apache-2.0
psmisc(pstree、fuser、killall)
你需要最接近的经典 Unix 等价物——pstree 显示父子树,fuser 查找使用文件或端口的进程,但两者都不重建带 systemd 单元标注的完整因果链。免费,GPL,多数 Linux 基础安装包含
lsof
你专门需要列出打开文件及持有进程(包括网络套接字),但不需要 witr 提供的祖先叙述。免费,许可证因发行版而异
glances
你想要基于 Python 的多维度系统监控器,带 Web UI 和可选的客户端-服务器模式,而非专注于谱系的诊断 CLI。免费,LGPL-3.0

这个趋势说明了什么

将 --json 输出接入值班手册

witr 的 --json 标志输出机器可读的因果链。SRE 团队可以用脚本在告警触发瞬间捕获链路,将完整祖先关系自动附加到事故工单中。

在演练场或真实机器上运行 witr --port <端口> --json 检查实际 JSON schema,然后在集成前编写对应的 jq 过滤器。

扩展 --container 支持 Kubernetes Pod 元数据

--container 标志已能遍历 Docker 等运行时的 cgroup 数据。贡献者可以增加一层映射,在 Kubernetes 节点上运行时将容器 ID 解析为 Pod 和命名空间标签。

在 cgroup 层级包含 kubelet 管理的容器运行时的真实 Kubernetes 节点上测试,验证 internal/ 中现有的 cgroup 遍历代码能访问 Pod 级别的 cgroup 目录。

添加期望与实际进程基线差异对比

由于 witr 打印完整的 systemd 祖先关系,一个包装脚本可以将今天的链路与某个服务存储的基线进行比对,标记意外出现的新子进程——适合部署后的漂移检测。

从具有已知服务的预发布主机采集基线,然后在下次部署后对生产主机运行差异对比,确认能捕获真实漂移而不会产生过多误报。

下一步建议

在浏览器演练场中运行 webbox 事故

打开 GitHub Pages 演练场,让冷启动事故自动播放,然后用 --port、--file、--pid 和 --verbose 解决 :8000 EADDRINUSE、dpkg 锁和 Node 应用资源占用三个任务。整个过程在 15 分钟内即可体验 witr 的核心因果链功能,无需安装任何东西。

  1. 访问 witr 的 GitHub Pages URL(从仓库链接进入)。
  2. 选择 webbox 场景,让冷启动事故播放完毕。
  3. 阅读简报和左侧任务追踪器。
  4. 运行 `witr --port 8000 --verbose` 追踪占用端口的 http.server。
  5. 运行 `witr --file /var/lib/dpkg/lock` 查找持有 dpkg 锁的 unattended-upgrade。
  6. 可选尝试 --json、--tree 和 --env 作为支线任务,然后查看进程星座视图观察因果链高亮效果。

RepoDaily 判断

witr 把 Linux 调试中最常见的问题——这为什么在跑?——转化为一条从目标到 systemd init 的可读因果链。bubbletea TUI、带逐字节 CI 保真度检查的零安装浏览器演练场,以及 Apache-2.0 单二进制分发方式,使它成为本周 Go 趋势榜上最易上手的诊断 CLI 之一。

信息来源