first commit

This commit is contained in:
2026-05-26 13:29:52 +05:00
commit 8fc452eb65
14 changed files with 998 additions and 0 deletions

241
README.md Normal file
View File

@@ -0,0 +1,241 @@
# rb-search
Консольная утилита для поиска по сообщениям в очередях RabbitMQ **без их потребления**.
## Что делает
1. Считывает глубину очереди `N` через `queue.declare-passive`.
2. Делает `N` раз `basic.get` с `autoAck=false` — сообщения становятся `unacked`,
для других консьюмеров очередь выглядит пустой, но физически они остаются на брокере.
3. В памяти проверяет каждое тело на подстроку и печатает совпадения (или все
сообщения, если фильтр не задан).
4. Делает `basic.nack(requeue=true)` по delivery-тегам **в обратном порядке**
каждое `nack` возвращает сообщение в голову очереди, и после прохода
очередь восстанавливается в исходном виде. Без дублей, без потери
`properties` / `headers` (сообщения ни разу не публикуются заново — это те же
фреймы с другим ack-состоянием).
На любой ветке выхода (ошибка, Ctrl+C, паника) defer гарантирует reverse-nack
до закрытия канала. Если по какой-то причине nack не успел — закрытие канала
автоматически возвращает unacked-сообщения, но порядок в этом случае не
гарантируется.
## Установка
Нужен Go 1.22+. Бинарь самодостаточный, без внешних зависимостей в рантайме.
### Из исходников (любая ОС)
```bash
git clone ssh://git@git.arx.ru:2222/shuricken/rb-search.git
cd rb-search
go build -o rb-search .
```
Готовый бинарь — `./rb-search`. Положить на `PATH`:
- Linux/macOS: `install -m 0755 rb-search ~/.local/bin/` или `sudo mv rb-search /usr/local/bin/`
- Windows (PowerShell): `Move-Item rb-search.exe $env:USERPROFILE\bin\`
### Через `go install`
```bash
go install git.arx.ru/shuricken/rb-search@latest
```
Бинарь окажется в `$(go env GOBIN)` (по умолчанию `~/go/bin`). Добавить в `PATH`:
- bash/zsh: `export PATH="$PATH:$(go env GOPATH)/bin"` в `~/.bashrc` / `~/.zshrc`
- fish: `fish_add_path (go env GOPATH)/bin`
- Windows: `setx PATH "%PATH%;%USERPROFILE%\go\bin"` (новые терминалы)
### Arch Linux
```bash
sudo pacman -S go
go install git.arx.ru/shuricken/rb-search@latest
```
### Debian / Ubuntu
```bash
sudo apt install golang-go
go install git.arx.ru/shuricken/rb-search@latest
```
Если в репозитории старый Go (< 1.22) — собрать из исходников после установки
`go` через `snap` или `gvm`.
### macOS
```bash
brew install go
go install git.arx.ru/shuricken/rb-search@latest
```
### Windows
1. Поставить Go с https://go.dev/dl/.
2. В PowerShell: `go install git.arx.ru/shuricken/rb-search@latest`.
3. Бинарь окажется в `%USERPROFILE%\go\bin\rb-search.exe`.
### Кросс-компиляция
С Linux собрать под другую платформу:
```bash
GOOS=darwin GOARCH=arm64 go build -o rb-search-darwin-arm64 .
GOOS=windows GOARCH=amd64 go build -o rb-search.exe .
```
## Конфигурация
Два независимых источника (приоритет — конфиг-файл, если он есть).
### JSON-конфиг
Путь поиска: `--config``$RB_SEARCH_CONFIG``$XDG_CONFIG_HOME/rb-search/config.json`
`~/.config/rb-search/config.json`.
Создать шаблон:
```bash
rb-search init
```
Формат:
```json
{
"default": "prod",
"servers": {
"local": {
"url": "amqp://guest:guest@localhost:5672/"
},
"prod": {
"url": "amqp://admin:secret@rabbit.prod:5672/myvhost"
},
"arx": {
"url": "amqp://admin:Rft5gasRer7H@10.49.150.156:5672/"
}
}
}
```
Управление:
```bash
rb-search list # показать серверы, default помечен *
rb-search set-default prod # сменить default
```
### Переменные окружения
Если конфиг-файла нет и заданы переменные — синтезируется сервер `env`, он же
default:
```bash
export EVENTBUS_AMQP_HOST=10.49.150.156 # обязательная
export EVENTBUS_AMQP_USER=admin
export EVENTBUS_AMQP_PASS=Rft5gasRer7H
export EVENTBUS_AMQP_PORT=5672 # опционально, по умолчанию 5672
export EVENTBUS_AMQP_VHOST= # опционально, по умолчанию /
rb-search --queue event
```
Существующий конфиг полностью имеет приоритет — env в этом случае игнорируется,
чтобы поведение было однозначным.
## Использование
```text
rb-search [flags] # читать default-сервер
rb-search --server NAME --queue Q # выбрать сервер вручную
rb-search list # список серверов
rb-search set-default NAME # сменить default
rb-search init # создать sample-конфиг
```
Флаги:
| Флаг | Назначение |
|----------------|-----------------------------------------------------------------------------------------------------|
| `--config PATH`| Путь к конфигу. |
| `--server NAME`| Имя сервера из конфига (override default). |
| `--queue NAME` | Очередь для сканирования (обязательный). |
| `--search S` | Подстрока для поиска в теле. Пусто — печатать все. |
| `--full` | Печатать полный конверт (exchange, routing-key, headers, properties). По умолчанию — только тело. |
| `--json` | Машинный вывод. С `--full` — объект-конверт; без `--full` — стрим тел. |
| `--max-body N` | Обрезать тело до N байт при печати (`0` — без ограничения). |
| `--timeout D` | Таймаут подключения, например `15s`. По умолчанию `30s`. |
### Матрица режимов вывода
| Флаги | stdout |
|-------------------|---------------------------------------------------------------------|
| `(default)` | Тело, pretty-print если JSON, маркер `--- #N tag=… ---` в stderr. |
| `--full` | Конверт + тело (тело pretty-print если JSON), человекочитаемо. |
| `--json` | Стрим тел: компактный JSON (если тело — JSON) или JSON-строка. |
| `--json --full` | Один JSON-объект на строку с полным конвертом; `body` — вложенный JSON, если разбирается. |
Диагностика (`queue "…" depth=N`, `scanned=N matched=M`, маркеры сообщений)
идёт в **stderr**, чтобы stdout оставался парсимым `jq`/файлом.
### Примеры
```bash
# Все сообщения как pretty JSON
rb-search --queue event
# Поиск с подсветкой (ANSI inverse video)
rb-search --queue event --search "OLV-3643"
# Полный конверт в человекочитаемом виде
rb-search --queue event --full
# Стрим тел через jq
rb-search --queue event --json | jq
# Собрать тела в массив
rb-search --queue event --json | jq -s .
# Извлечь поле из каждого тела
rb-search --queue event --json --search change | jq '.offerAcceptance.id'
# Полные сообщения с разобранным body
rb-search --queue event --json --full | jq '.body.action'
# Только тела в файл
rb-search --queue event > bodies.txt # маркеры остались в терминале (stderr)
# Без болтовни
rb-search --queue event --json 2>/dev/null | jq
# Другой сервер из конфига
rb-search --server prod --queue billing.events --search "invoice-42"
# С env-переменными, без конфиг-файла
EVENTBUS_AMQP_HOST=10.49.150.156 EVENTBUS_AMQP_USER=admin EVENTBUS_AMQP_PASS=Rft5gasRer7H \
rb-search --queue event
```
### Коды выхода
- `0` — успех (включая отсутствие совпадений).
- `1` — ошибка рантайма (нет коннекта, не существует очередь, ошибка AMQP, …).
- `2` — неверное использование флагов.
## Ограничения
- Очередь должна существовать. `queue.declare-passive` сначала пробуется как
`durable`, при mismatch — переоткрывается канал и пробуется как
non-durable. Декларация с `auto-delete=true` / `exclusive=true` может не
совпасть — это редко мешает на практике.
- `basic.get` читает только то, что есть в очереди на момент старта. Сообщения,
пришедшие во время сканирования, будут увидены при следующем запуске.
- Поиск — побайтовый `Contains` по сырому телу. Если тело сжато
(`content-encoding: gzip`), искать нужно по сжатому представлению или
разжимать руками.
- Параллельно работающие консьюмеры на этой же очереди в момент сканирования
будут видеть очередь как «пустую» — это нормально, после reverse-nack
обычная работа возобновится.