← All one-liners·#083·diagnostics·self contained·beginner

Answer 'why is this running?' as structured JSON

witr traces a process, port, container, or held file back to what started it — the question every incident starts with — and its --json flag turns the answer into a jq-queryable object instead of a wall of ps/lsof output you'd normally stitch together by hand.

Setup
  • → curl -fsSL https://github.com/pranshuparmar/witr/releases/download/v0.3.3/witr-linux-amd64 -o witr && curl -fsSL https://github.com/pranshuparmar/witr/releases/download/v0.3.3/SHA256SUMS -o SHA256SUMS && grep witr-linux-amd64 SHA256SUMS | sha256sum -c - && chmod +x witr && sudo mv witr /usr/local/bin/witr (or: brew install witr / go install github.com/pranshuparmar/witr/cmd/witr@v0.3.3 — avoid piping the mutable main-branch install.sh into bash)
Cost per run
free
The one-liner
$ set -o pipefail && ( sleep 300 & pid=$!; trap 'kill $pid 2>/dev/null' EXIT; sleep 0.1; witr --pid "$pid" --json \
  | jq '{pid: .Process.PID, cmd: .Process.Cmdline, resolved: .ResolvedTarget, user: .Process.User, started_at: .Process.StartedAt}' )
What each stage does
  1. [01] sleep( sleep 300 & pid=$!; trap 'kill $pid 2>/dev/null' EXIT; sleep 0.1; ...; )
    Stands in for 'some process you're investigating' — swap $pid for a real PID (witr --pid 1234), a port (witr --port 5432), or a held file (witr --file /var/lib/dpkg/lock) in practice. The subshell + EXIT trap kills the demo process afterward instead of leaking it; the short sleep gives /proc time to populate before witr reads it.
  2. [02] witrwitr --pid "$pid" --json
    Resolves the target to a process and reports its ancestry, working directory, resource usage, and health as one JSON object. --tree instead prints the full parent chain; --warnings flags suspicious env vars or arguments. witr exits non-zero even on a clean trace — 1 means it found warnings (e.g. running as root), which pipefail (above) makes visible instead of letting jq's exit 0 hide it.
  3. [03] jqjq '{pid: .Process.PID, cmd: .Process.Cmdline, resolved: .ResolvedTarget, user: …
    Picks a handful of fields for a scripted check — CI smoke tests, deploy verification, or monitoring integrations can assert on this instead of screen-scraping ps.
Expected output (sample)
{
  "pid": 3717,
  "cmd": "sleep 300",
  "resolved": "sleep",
  "user": "root",
  "started_at": "2026-09-01T16:11:14.25Z"
}
Caveats & tips
  • Captured with witr v0.3.3 (released 2026-06-24) on Linux; PID and timestamp will differ every run — this is a live process snapshot, not a fixture.
  • The full JSON payload includes the target process's entire environment under .Process.Env — pipe through jq to select only the fields you need before logging or sharing it, since env vars routinely carry tokens and credentials.
  • In a container/sandbox without a health-check supervisor, .Health may come back null rather than "healthy"/"unhealthy" — that's expected, not a bug.
  • witr's exit code encodes outcome, not just success: 0 = clean, 1 = process found but with warnings (root, 0.0.0.0 listeners, LD_PRELOAD, ...), 2 = not found, 3 = permission denied. Verified in-sandbox: tracing our own sleep process while running as root produces exit 1 even though the JSON trace itself is complete and correct — pipefail is what surfaces that, not a sign the command failed.