# 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-сообщения, но порядок в этом случае не гарантируется. ## Установка ### Готовые бинари (рекомендуется) Собранные релизы лежат на странице [Releases](https://git.arx.ru/shuricken/rb-search/releases) — Linux/macOS/Windows, amd64 и arm64. Скачать соответствующий файл, проверить контрольную сумму из `SHA256SUMS` и положить на `PATH`: ```bash # Linux/macOS, под свою архитектуру curl -LO https://git.arx.ru/shuricken/rb-search/releases/download/vX.Y.Z/rb-search-vX.Y.Z-linux-amd64 curl -LO https://git.arx.ru/shuricken/rb-search/releases/download/vX.Y.Z/SHA256SUMS sha256sum --ignore-missing -c SHA256SUMS chmod +x rb-search-* sudo mv rb-search-* /usr/local/bin/rb-search ``` ```powershell # Windows PowerShell Invoke-WebRequest -OutFile rb-search.exe ` https://git.arx.ru/shuricken/rb-search/releases/download/vX.Y.Z/rb-search-vX.Y.Z-windows-amd64.exe Move-Item rb-search.exe $env:USERPROFILE\bin\ ``` Проверка установки: `rb-search version` → печатает версию. ### Из исходников Нужен 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:REDACTED@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=REDACTED 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=REDACTED \ 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 обычная работа возобновится.