
sonar v0.4.1
CLI-Tool zum Inspizieren und Verwalten von Diensten, die auf Localhost-Ports lauschen.
██████ ███ ██████ ██ ██████
██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ████
██ ██ ██ ██ ██ ██ ██ ██
██████ ███ ██ ██ ██ ██ ██ ██
Erfahre, was auf deiner Maschine läuft.
Sonar zeigt alles an, was auf localhost lauscht, und bringt es in Ordnung: Jeder Port
gehört zu einer Gruppe – normalerweise das Repository, aus dem er gestartet wurde – und
innerhalb dieser Gruppe zu einem benannten Dienst. Starte deine Dev-Server mit
sonar start, und das gesamte Projekt wird zu einer einzigen Sache, die du als Baum auflisten,
auf die du warten, die du verfolgen und mit einem einzigen Befehl stoppen kannst. Docker-Container, Compose-
Projekte und Prozesse, die du von Hand gestartet hast, werden ebenfalls erfasst, ohne jegliche
Konfiguration.
$ sonar list --tree
my-app (3 ports, running) ~/code/my-app
├─ 5432 db postgres:17 http://localhost:5432
├─ 5173 frontend vite (v5.4) http://localhost:5173
└─ 8000 api uvicorn app:app http://localhost:8000
ungrouped (1 port)
└─ 3000 next-server (v16.1.6) http://localhost:3000
Installation
Homebrew (macOS / Linux)
brew install raskrebs/sonar/sonar
Homebrew 6 verweigert Formeln aus Drittanbieter-Taps, bis du den Tap einmal vertraust
(Error: Refusing to load formula raskrebs/sonar/sonar from untrusted tap):
brew trust raskrebs/sonar
Installationsskript
curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | bash
Lädt die neueste Binärdatei nach ~/.local/bin herunter und fügt sie bei Bedarf zu deinem PATH hinzu. Starte dein Terminal neu oder führe source ~/.zshrc aus.
Unter Windows (PowerShell):
irm https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.ps1 | iex
Benutzerdefinierter Installationspfad:
curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | SONAR_INSTALL_DIR=/usr/local/bin bash
Installiere eine bestimmte Version:
curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | SONAR_VERSION=vX.Y.Z bash
$env:SONAR_VERSION="vX.Y.Z"; irm https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.ps1 | iex
Verwendung von Go
go install github.com/raskrebs/sonar@latest
Shell-Vervollständigungen (Tab-Vervollständigung für Portnummern):
sonar completion zsh > "${fpath[1]}/_sonar" # zsh
sonar completion bash > /etc/bash_completion.d/sonar # bash
sonar completion fish | source # fish
Sechzig Sekunden
Beschreibe, wie dein Projekt läuft, in einer sonar.yaml im Repository-Stammverzeichnis,
anstelle einer dev.sh:
name: my-app
services:
- name: db
cmd: docker compose up db
port: 5432
- name: api
cmd: uv run uvicorn app:app --port ${port}
port: auto
depends_on: [db]
- name: frontend
cmd: npm run dev -- --port ${port} --strictPort
port: auto
depends_on: [api]
env:
VITE_API_URL: ${api.url}
Dann starte es:
sonar start
✓ db http://localhost:5432 pid 41022 ~/.config/sonar/logs/my-app/db.log
✓ api http://localhost:21408 pid 41040 ~/.config/sonar/logs/my-app/api.log
✓ frontend http://localhost:21409 pid 41077 ~/.config/sonar/logs/my-app/frontend.log
3 started
following the logs; Ctrl+C stops the 3 services started here
api | INFO: Uvicorn running on http://127.0.0.1:21408
frontend | VITE v5.4 ready in 312 ms
Sonar wählt einen freien Port für jeden port: auto-Dienst und teilt jedem Dienst mit,
wo sich die anderen befinden, sodass ein zweiter Worktree neben dem ersten läuft, ohne
dass ein einziger Port kollidiert. sonar start -d macht dasselbe im Hintergrund, und
sonar down stoppt ihn und gibt die Ports zurück. In einem anderen Terminal:
sonar list --tree
my-app (3 ports, running) ~/code/my-app
├─ 5432 db postgres:17 http://localhost:5432
├─ 21408 api uvicorn app:app http://localhost:21408
└─ 21409 frontend vite (v5.4) http://localhost:21409
Keine sonar.yaml? sonar start -- npm run dev führt einen Befehl als benannten
Dienst aus, und sonar list und sonar kill funktionieren mit allem, was lauscht.
Die unten mit # check markierten Beispiele werden bei jedem CI-Lauf gegen einen frischen Build
durch scripts/readme-check.sh ausgeführt.
Befehle
sonar list
sonar list
sonar list --tree
sonar list --group my-app
sonar list --json
# check
sonar list --stats # CPU, memory, threads, uptime, state
sonar list --health # HTTP health checks
sonar list --filter docker # only Docker ports
sonar list --sort name # port | pid | name | type
sonar list -a # include desktop apps
sonar list -c port,process,group,cpu,mem
sonar list --host user@server # scan a remote machine over SSH
Standardspalten sind port, process, group, container, image,
containerport, url, wobei process den Namen anzeigt, den du dem Port gegeben hast
(sonar rename), dann den Dienstnamen, dann das, was erkannt wurde.
Verfügbare Spalten: port, process, pid, type, url, group, cpu,
mem, threads, uptime, state, connections, health, latency,
container, image, containerport, compose, project, user, bind,
ip.
Desktop-Apps und Systemdienste, die zufällig lauschen — Figma, Discord,
Spotify, ControlCenter, macOS .app-Bundles, /System/Library/-Daemons — werden
ausgeblendet, es sei denn, du übergibst -a.
sonar start
Starte ein Projekt aus seiner sonar.yaml:
sonar start # every service in the nearest sonar.yaml
sonar start api frontend # only these (they still wait for their dependencies)
sonar start ../other-project # the sonar.yaml in or above another directory
sonar start -d # in the background, like `sonar up`
Im Vordergrund startet sonar die Dienste über den Daemon, verfolgt deren Logs mit dem Dienstnamen vor jeder Zeile und stoppt bei Drücken von Ctrl+C die Dienste, die es gestartet hat. Ein Dienst, der bereits lief, wird in Ruhe gelassen, und sonar kehrt von selbst zurück, sobald jeder von ihm gestartete Dienst beendet wurde.
Argumente vor -- benennen ein Verzeichnis oder Dienste; alles nach -- ist ein
Befehl. Oder führe einen Befehl als benannten Dienst in einer Gruppe aus:
sonar start -- npm run dev
sonar start --group my-app --name frontend -- npm run dev
sonar start --port 5173 -- npm run dev # expected port, before it binds
sonar start --detach --name api -- uv run uvicorn app:app
sonar start --list
Nichts muss übergeben werden:
- Group —
--group, sonst dernamein der nächstgelegenensonar.yaml, sonst der Verzeichnisname des Git-Roots (ein Worktree wird zurepo@worktree), sonst der Name des aktuellen Verzeichnisses. - Name —
--name, sonst dersonar.yaml-Service, dessencmdübereinstimmt, sonst abgeleitet aus dem Befehl (npm run dev→dev,uv run api→api,python -m uvicorn→uvicorn,./dev.sh→dev.sh). - Port —
--portist ein Hinweis, keine Bindung: Der Lauf wird alsstartingangezeigt, bis der Port tatsächlich lauscht, und der Daemon verwendet ihn, um den Prozess dem Port zuzuordnen.
Das Kind erbt stdin, stdout, stderr, cwd und die Umgebung sowie SONAR_GROUP, SONAR_NAME und SONAR_RUN_ID. Es erhält eine eigene Prozessgruppe, sodass sonar kill den gesamten Baum beendet — einen Dev-Server mit seinen Watchern und Workern. Ctrl+C wird weitergeleitet, und sonar beendet sich mit dem Exit-Code des Kindes.