
sonar v0.4.1
Strumento CLI per ispezionare e gestire i servizi in ascolto sulle porte di localhost
██████ ███ ██████ ██ ██████
██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ████
██ ██ ██ ██ ██ ██ ██ ██
██████ ███ ██ ██ ██ ██ ██ ██
Know what's running on your machine.
Sonar mostra tutto ciò che è in ascolto su localhost e lo mette in ordine: ogni porta
appartiene a un gruppo — normalmente il repository da cui è stato avviato — e
all'interno di quel gruppo a un servizio con nome. Avvia i tuoi server di sviluppo con
sonar start e l'intero progetto diventa un'unica cosa che puoi elencare come un albero,
attendere, seguire e fermare con un singolo comando. Anche i container Docker, i progetti
Compose e i processi avviati manualmente vengono rilevati, senza alcuna
configurazione.
$ 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
Installazione
Homebrew (macOS / Linux)
brew install raskrebs/sonar/sonar
Homebrew 6 rifiuta le formule provenienti da tap di terze parti finché non ti fidi del tap una volta
(Error: Refusing to load formula raskrebs/sonar/sonar from untrusted tap):
brew trust raskrebs/sonar
Script di installazione
curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | bash
Scarica l'ultimo binario in ~/.local/bin e lo aggiunge al tuo PATH se necessario. Riavvia il terminale o esegui source ~/.zshrc.
Su Windows (PowerShell):
irm https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.ps1 | iex
Percorso di installazione personalizzato:
curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | SONAR_INSTALL_DIR=/usr/local/bin bash
Installa una versione specifica:
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
Utilizzo di Go
go install github.com/raskrebs/sonar@latest
Shell completions (tab-complete port numbers):
sonar completion zsh > "${fpath[1]}/_sonar" # zsh
sonar completion bash > /etc/bash_completion.d/sonar # bash
sonar completion fish | source # fish
Sessanta secondi
Descrivi come viene eseguito il tuo progetto in un sonar.yaml nella radice del repository, al posto di un 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}
Poi avvialo:
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 sceglie una porta libera per ogni servizio port: auto e comunica a ciascun servizio dove si trovano gli altri, così un secondo worktree viene eseguito accanto al primo senza che una singola porta entri in conflitto. sonar start -d fa lo stesso in background, e sonar down lo arresta e restituisce le porte. In un altro terminale:
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
Nessun sonar.yaml? sonar start -- npm run dev esegue un singolo comando come servizio con nome, e sonar list e sonar kill funzionano su qualsiasi cosa sia in ascolto.
Gli esempi seguenti contrassegnati con # check vengono eseguiti su una build appena creata da scripts/readme-check.sh a ogni esecuzione della CI.
Comandi
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
Le colonne predefinite sono port, process, group, container, image,
containerport, url, dove process mostra il nome che hai assegnato alla porta
(sonar rename), poi il nome del servizio, poi ciò che è stato rilevato.
Colonne disponibili: port, process, pid, type, url, group, cpu,
mem, threads, uptime, state, connections, health, latency,
container, image, containerport, compose, project, user, bind,
ip.
Le app desktop e i servizi di sistema che si trovano in ascolto — Figma, Discord,
Spotify, ControlCenter, bundle .app di macOS, daemon in /System/Library/ — sono
nascosti a meno che tu non passi -a.
sonar start
Avvia un progetto dal suo 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`
In primo piano, sonar avvia i servizi tramite il daemon, segue i loro log con il nome del servizio davanti a ogni riga, e quando premi Ctrl+C ferma i servizi che ha avviato. Un servizio già in esecuzione viene lasciato in pace, e sonar ritorna da solo una volta che ogni servizio che ha avviato è terminato.
Gli argomenti prima di -- indicano una directory o dei servizi; tutto ciò che segue -- è un
comando. Oppure esegui un comando come servizio con nome in un gruppo:
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
Non deve essere passato nulla:
- Group —
--group, altrimenti ilnamenelsonar.yamlpiù vicino, altrimenti il nome della directory della radice git (un worktree diventarepo@worktree), altrimenti il nome della directory corrente. - Name —
--name, altrimenti il serviziosonar.yamlil cuicmdcorrisponde, altrimenti inferito dal comando (npm run dev→dev,uv run api→api,python -m uvicorn→uvicorn,./dev.sh→dev.sh). - Port —
--portè un suggerimento, non un binding: l'esecuzione appare comestartingfinché la porta non è effettivamente in ascolto, e il daemon la usa per associare il processo alla porta.
Il processo figlio eredita stdin, stdout, stderr, cwd e l'ambiente, più
SONAR_GROUP, SONAR_NAME e SONAR_RUN_ID. Ottiene il proprio process group,
così sonar kill abbatte l'intero albero — un dev server con i suoi watcher e
worker. Ctrl+C viene inoltrato, e sonar esce con il codice di uscita del figlio.