
sonar v0.4.1
localhost 포트에서 수신 중인 서비스를 검사하고 관리하기 위한 CLI 도구
██████ ███ ██████ ██ ██████
██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ████
██ ██ ██ ██ ██ ██ ██ ██
██████ ███ ██ ██ ██ ██ ██ ██
여러분의 머신에서 무엇이 실행 중인지 파악하세요.
Sonar는 localhost에서 수신 대기 중인 모든 것을 보여주고 정리합니다: 모든 포트는
그룹에 속하며 — 일반적으로 해당 포트가 시작된 저장소 — 그 그룹 내에서는
이름이 지정된 서비스에 속합니다. sonar start로 개발 서버를 시작하면
프로젝트 전체가 하나의 트리로 나열하고, 대기하고, tail하고, 단일 명령으로
중지할 수 있는 하나의 대상이 됩니다. Docker 컨테이너, Compose 프로젝트,
직접 시작한 프로세스도 별도 설정 없이 함께 감지됩니다.
$ 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
설치
Homebrew (macOS / Linux)
brew install raskrebs/sonar/sonar
Homebrew 6은 신뢰할 수 있는 탭으로 한 번 신뢰할 때까지 서드파티 탭의 포뮬러를 거부합니다
(Error: Refusing to load formula raskrebs/sonar/sonar from untrusted tap):
brew trust raskrebs/sonar
설치 스크립트
curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | bash
최신 바이너리를 ~/.local/bin에 다운로드하고 필요하면 PATH에 추가합니다. 터미널을 재시작하거나 source ~/.zshrc를 실행하세요.
Windows(PowerShell)에서는:
irm https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.ps1 | iex
사용자 지정 설치 위치:
curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | SONAR_INSTALL_DIR=/usr/local/bin bash
특정 버전 설치:
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
Go 사용하기
go install github.com/raskrebs/sonar@latest
셸 자동 완성(탭으로 포트 번호 자동 완성):
sonar completion zsh > "${fpath[1]}/_sonar" # zsh
sonar completion bash > /etc/bash_completion.d/sonar # bash
sonar completion fish | source # fish
60초
저장소 루트의 dev.sh 대신 sonar.yaml에 프로젝트가 어떻게 실행되는지 설명하세요:
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}
그런 다음 시작하세요:
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는 모든 port: auto 서비스에 대해 사용 가능한 포트를 선택하고 각 서비스에 다른 서비스의 위치를 알려주므로, 두 번째 worktree가 첫 번째 옆에서 포트 충돌 없이 실행됩니다. sonar start -d는 백그라운드에서 동일한 작업을 수행하며, sonar down은 이를 중지하고 포트를 반환합니다. 다른 터미널에서:
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
sonar.yaml이 없나요? sonar start -- npm run dev는 하나의 명령을 이름이 지정된 서비스로 실행하며, sonar list와 sonar kill은 수신 대기 중인 모든 항목에 대해 작동합니다.
아래에서 # check로 표시된 예제는 매 CI 실행 시 scripts/readme-check.sh에 의해 새 빌드에 대해 실행됩니다.
명령어
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
기본 열은 port, process, group, container, image,
containerport, url이며, 여기서 process는 포트에 지정한 이름
(sonar rename)을, 그다음 서비스 이름을, 그다음 감지된 항목을
표시합니다.
사용 가능한 열: port, process, pid, type, url, group, cpu,
mem, threads, uptime, state, connections, health, latency,
container, image, containerport, compose, project, user, bind,
ip.
우연히 리스닝 중인 데스크톱 앱과 시스템 서비스 — Figma, Discord,
Spotify, ControlCenter, macOS .app 번들, /System/Library/ 데몬 — 는
-a를 전달하지 않는 한 숨겨집니다.
sonar start
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`
포그라운드에서 sonar는 데몬을 통해 서비스를 시작하고, 모든 줄 앞에 서비스 이름을 붙여 로그를 따라가며, Ctrl+C를 누르면 자신이 시작한 서비스를 중지합니다. 이미 실행 중이던 서비스는 그대로 두고, sonar가 시작한 모든 서비스가 종료되면 sonar도 스스로 종료됩니다.
-- 앞의 인수는 디렉터리나 서비스를 지정하며, -- 뒤의 모든 것은 명령입니다. 또는 하나의 명령을 그룹 내 이름 있는 서비스로 실행할 수도 있습니다:
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
아무것도 전달할 필요가 없습니다:
- Group —
--group, 그렇지 않으면 가장 가까운sonar.yaml의name, 그렇지 않으면 git 루트의 디렉터리 이름(워크트리는repo@worktree가 됨), 그렇지 않으면 현재 디렉터리의 이름. - Name —
--name, 그렇지 않으면cmd가 일치하는sonar.yaml서비스, 그렇지 않으면 명령에서 추론됨(npm run dev→dev,uv run api→api,python -m uvicorn→uvicorn,./dev.sh→dev.sh). - Port —
--port는 힌트일 뿐 바인딩이 아닙니다: 포트가 실제로 리스닝될 때까지 실행은starting으로 표시되며, 데몬은 이를 사용해 프로세스를 포트에 매칭합니다.
자식 프로세스는 stdin, stdout, stderr, cwd 및 환경을 상속받고, 추가로
SONAR_GROUP, SONAR_NAME, SONAR_RUN_ID를 받습니다. 자체 프로세스 그룹을
가지므로 sonar kill이 전체 트리 — 워처와 워커를 포함한 개발 서버 — 를
종료시킵니다. Ctrl+C는 전달되며, sonar는 자식의 종료 코드로 종료됩니다.
--detach는 즉시 반환하고 출력을
~/.config/sonar/logs/<group>/<name>.log에 기록합니다. --list는 sonar가 시작한
것과 그 아래에 이후 종료된 것 — 종료 코드, 그리고 크래시했는지 중지되었는지와
함께 — 을 보여줍니다(기계 판독 가능한 형식은 --json):
sonar start --list
sonar start --detach --name demo --port 8123 -- sleep 5
sonar start --list --json
# check
sonar.yaml
프로젝트는 저장소 루트의 sonar.yaml에서 자신과 서비스를 명명합니다. 이 파일은 선택 사항이며 — sonar는 없어도 git 루트를 기준으로 그룹화합니다 — 커밋하는 것을 의도한 것입니다:
name: my-app
services:
- name: db
cmd: docker compose up db
port: 5432
health: /
description: Postgres 17
icon: database
color: "#4f8cc9"
- name: api
cmd: uv run uvicorn app:app --port 8000
cwd: backend
port: 8000
health: /healthz
depends_on: [db]
- name: frontend
cmd: npm run dev
port: 5173
depends_on: [api]
ports: [9229] # ports that belong to this project without a service
name— 그룹 이름. 슬래시 없음, 공백 없음.cmd,cwd,port—sonar start가 서비스를 시작하는 방식.cwd는 파일 기준 상대 경로이며 해당 디렉터리를 벗어날 수 없다.health— 서비스가 실행 중일 때 데몬이 폴링하는 HTTP 경로로, 서비스가 실행 중이지만 아직 정상이 아닐 수 있다.ok,fail또는unknown을 보고하며, 실패 시 그 이유를 함께 보고한다.description,icon,color— 데스크톱 앱을 위한 자유 형식 메타데이터로, sonar는 이를 절대 추론하지 않는다.depends_on— 시작 순서. 파일에 없는 서비스를 지정하거나 순환이 있으면 오류이다. 유효하지 않은 파일은 한 번 보고되며 스캔을 중단시키지 않는다.env— sonar가 서비스를 시작할 때 해당 서비스에 설정되는 변수.
port: auto와 참조
서비스는 포트를 sonar에 맡길 수 있으며, 하드코딩된 localhost:8080 대신
환경 변수를 통해 다른 서비스를 찾을 수 있다: