witr 开源进程追踪工具:一条命令还原进程因果链

登录一台 Linux 服务器,ps aux 列出一堆进程,其中一个占了大量内存的 node 你完全不记得是谁拉起来的。端口 5000 在 LISTEN,但 lsof -i :5000 只给了你一个 PID,你得手动翻 systemd unit、PM2 进程树、Docker 容器列表,拼凑出这条因果链。witr 把这个手动过程自动化了——一条命令输出从 PID 1 到目标进程的完整起源链,外加容器检测、安全告警和交互式 TUI。

GitHub 上 pranshuparmar/witr 用 Go 写成,单二进制文件,20,600 星,支持 Linux、macOS、Windows 和 FreeBSD 四大平台,已进入 Debian sid、Homebrew、Conda、Winget 等十余个官方包管理器。作者 Pranshu Parmar 在 Hacker News 上的 Show HN 帖获得了 526 分。

witr 的 TUI 交互界面,左侧进程列表选中 node 进程,右侧显示完整因果链和上下文

核心概念:一切皆是进程问题

witr 的设计哲学是「一切皆是进程问题」。端口、服务、容器、文件锁,最终都映射到 PID。拿到 PID 后,witr 构建一条因果链解释这个 PID 为什么存在。

传统工具的分工是割裂的:ps 显示进程列表,top 显示资源占用,lsof 显示打开的文件和端口,systemctl status 显示服务状态,docker ps 显示容器列表。每条工具只回答「什么在运行」,用户需要自己跨工具关联输出来推断「为什么在运行」。witr 做的就是把这层推断自动化。

它回答四个问题:

  1. 什么在运行?
  2. 它怎么启动的?
  3. 什么在维持它运行?
  4. 它属于什么上下文?

因果链构建

witr 最核心的输出是「Why It Exists」段——一条从 PID 1 到目标进程的祖先链。以一个由 PM2 管理的 node 进程为例:

text
Why It Exists:
  systemd (pid 1) → pm2 (pid 5034) → node (pid 14233)

这不同于简单的 ppid 递归。witr 在每一跳上做语义识别,判断当前节点是 systemd unit、launchd 服务、SSH 会话、Docker 容器、PM2 管理器、cron 任务、交互式 shell、还是 Snap/Flatpak 沙箱,并在输出中标注。

Source 字段选出一个主要责任方,例如 systemd unit(附带 timer 调度信息)、launchd plist(附带触发器详情)、Docker compose 项目、或 SSH 远程会话(附带 IP 和终端)。

Context 段提供工作目录、Git 仓库名和分支、容器名和镜像、监听地址是公网还是内网。

查询模式

witr 支持五种查询入口,全部可混合使用:

按名称查询——默认子串模糊匹配,加 -x 走精确匹配:

bash
witr node          # 匹配所有含 "node" 的进程
witr nginx -x      # 只匹配精确名为 nginx 的进程

输出示例:

text
Target      : node
Process     : node (pid 14233)
User        : pm2
Command     : node index.js
Started     : 2 days ago (Mon 2026-02-02 11:42:10 +05:30)

Why It Exists:
  systemd (pid 1) → pm2 (pid 5034) → node (pid 14233)

Source      : pm2
Working Dir : /opt/apps/expense-manager
Git Repo    : expense-manager (main)
Sockets     : 127.0.0.1:5001 (TCP | LISTENING)

按端口查询——快速定位谁占用了端口,附带完整因果链:

bash
witr --port 5000 --short
# systemd (pid 1) → PM2 v5.3.1: God (pid 1481580) → python (pid 1482060)

按 PID 查询 + 树形输出——展示包含子进程的完整进程树:

bash
witr --pid 143895 --tree
text
systemd (pid 1)
  └─ init-systemd(Ub (pid 2)
    └─ SessionLeader (pid 143858)
      └─ Relay(143860) (pid 143859)
        └─ bash (pid 143860)
          └─ sh (pid 143886)
            └─ node (pid 143895)
              ├─ node (pid 143930)
              ├─ node (pid 144189)
              └─ node (pid 144234)

按文件查询——找出哪个进程持有文件:

bash
witr --file /var/lib/dpkg/lock

按容器查询——跨运行时搜索:

bash
witr --container redis

--container 标志会搜索 Docker、Podman、nerdctl、K8s/crictl、Incus、LXC、LXD 和 FreeBSD jails,按容器名、镜像名、启动命令或 compose 项目/服务名匹配。加 --verbose 可输出挂载、网络和 compose 元数据。

多个输入可混用,结果按输入顺序分段输出。所有输出模式(--short--tree--json--env--warnings--verbose)都兼容多输入。

安全告警

witr 在追踪进程的同时做安全检查,遇到以下情况会在 Warnings 段标出:

  • 进程以 root 身份运行
  • 非 root 进程持有危险 Linux capabilities(CAP_SYS_ADMIN 等)
  • 进程监听在公网接口(0.0.0.0 / ::)
  • 进程重启次数超过阈值
  • 内存占用超过 1GB RSS
  • 运行时间超过 90 天
  • 二进制文件已被删除(可能被入侵后替换)
  • LD_PRELOAD / DYLD 注入指标

--warnings 模式只输出告警,适合在 CI 管道或监控脚本中使用。

交互式 TUI

不带参数运行 witr 或加 -i 标志进入交互式 TUI,提供四个标签页:

  • Processes:所有运行中进程的实时列表,支持排序和过滤,右侧面板展示选中进程的祖先树
  • Ports:所有监听/打开端口,按 a 切换 LISTEN-only 和全部,右侧附带归属进程
  • Containers:跨 Docker、Podman、nerdctl、K8s、Incus、LXC、LXD、FreeBSD jails 的统一容器列表,含名称、镜像、状态、端口、命令,点击可查看挂载和网络详情
  • Locks:系统级文件锁(Linux POSIX/FLOCK,macOS/FreeBSD 从 lsof 派生),按 a 切换为「所有打开文件」模式

TUI 支持鼠标操作(导航、排序、点击行),自适应明暗终端主题,进程/端口/容器/锁列表以 3 秒为基准自动刷新(高负载下自动退避)。Unix 平台上可直接在 UI 中对进程发送信号(Kill、Terminate、Pause、Resume)或调整 nice 值。

跨平台架构

witr 在每个平台上用原生 API 直采数据,不依赖外部命令拼装:

平台数据采集方式
Linux/proc 文件系统直读
macOSpslsofsysctlpgreplaunchctl
WindowsWin32 原生 API(ToolHelp32、PSAPI、Service Control Manager),不依赖 PowerShell 或 WMI
FreeBSDprocstatpslsof

Windows 版本值得注意:它不经过 PowerShell 或 WMI,启动快,不会出现 Get-CimInstance 挂起问题。这对在 Windows Server 上做运维排查的团队是一个实际优势。

跨平台功能支持存在差异。环境变量查看在 macOS 受 SIP 限制,Windows 上受保护进程不可读。tmux/screen 检测不支持 Windows。调度检测(systemd timers / launchd intervals)不支持 Windows 和 FreeBSD。文件锁在 Windows 上只返回计数。完整矩阵见仓库 README 的 Feature Compatibility Matrix。

服务管理器检测

witr 在每个平台上识别不同的 init 系统:

  • Linux: systemd(含 unit 文件路径、timer 调度信息、服务描述)
  • macOS: launchd(含 plist 路径、触发器详情)
  • Windows: Services(含注册表键、Display Name)
  • FreeBSD: rc.d(含 rc 脚本路径、rc 头描述)

检测到容器运行时后,witr 能穿透容器边界追踪宿主进程和容器内进程的关系,包括 Docker compose 项目/服务映射。

SSH 会话检测支持所有四个平台,会输出远程 IP 和终端信息。tmux/screen 检测会在 Source 段显示会话名。

安装

最常用的三种方式:

bash
# Homebrew (macOS/Linux)
brew install witr

# Debian/Ubuntu (sid/26.04+)
sudo apt install witr

# Conda (全平台)
conda install -c conda-forge witr

Windows 上可通过 Winget、Chocolatey 或 Scoop 安装。npm 也可安装(npm install -g @pranshuparmar/witr),走二进制下载而非 Node.js 运行时。Go 开发者可以直接 go install github.com/pranshuparmar/witr/cmd/witr@latest

安装脚本一键安装(Linux/macOS/FreeBSD):

bash
curl -fsSL https://raw.githubusercontent.com/pranshuparmar/witr/main/install.sh | bash

首次使用建议直接在浏览器试用,作者提供了交互式在线教程(pranshuparmar.github.io/witr),在一个模拟 Linux 环境中走完查询流程,无需安装。

退出码

witr 定义了六个退出码,方便脚本化集成:

含义
0进程已找到,无告警
1进程已找到,有告警
2未找到匹配进程或服务
3权限不足
4输入无效或匹配歧义
5内部错误

示例集成:

bash
witr nginx --short
case $? in
  0) echo "All clear" ;;
  1) echo "Warnings detected" ;;
  2) echo "Process not running" ;;
  3) echo "Need elevated privileges" ;;
esac

适用场景

witr 解决的核心痛点是运维排障中的「这个进程到底是谁拉起来的」。典型场景包括:

  • 登录一台陌生服务器,快速理解进程拓扑
  • 生产事故排查,几秒内定位异常进程的来源
  • 安全审计,快速发现 root 运行、公网暴露、二进制替换等异常
  • 容器化环境调试,跨运行时统一查看容器状态
  • CI/CD 管道中自动化检测风险进程

对于经常需要在多台机器间切换的 SRE 和 DevOps 工程师,witr 把 ps + lsof + ss + systemctl + docker ps 的手动关联流程压缩到一条命令。单二进制、零运行时依赖、六大包管理器分发的设计,让它可以在任何机器上几秒部署。