Files
rb-search/README.md
Alex Shlyakhov be3251716c
Some checks failed
release / release (push) Has been cancelled
Build infrastructure for releases
- Makefile: cross-compile to linux/{amd64,arm64}, darwin/{amd64,arm64},
  windows/amd64 into dist/ with SHA256SUMS. Version is stamped via
  -ldflags '-X main.version=...'.
- .gitea/workflows/release.yml: on tag push (v*) the workflow runs
  `make dist`, creates a Gitea release for the tag and uploads every
  artefact from dist/ via the Gitea API.
- main.go: `rb-search version` / --version prints the stamped version.
- README: new "Готовые бинари" section with curl/Invoke-WebRequest
  install snippets and a checksum-verify hint.
2026-05-26 13:46:16 +05:00

12 KiB
Raw Blame History

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 — Linux/macOS/Windows, amd64 и arm64. Скачать соответствующий файл, проверить контрольную сумму из SHA256SUMS и положить на PATH:

# 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
# 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+. Бинарь самодостаточный, без внешних зависимостей в рантайме.

Любая ОС

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

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

sudo pacman -S go
go install git.arx.ru/shuricken/rb-search@latest

Debian / Ubuntu

sudo apt install golang-go
go install git.arx.ru/shuricken/rb-search@latest

Если в репозитории старый Go (< 1.22) — собрать из исходников после установки go через snap или gvm.

macOS

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 собрать под другую платформу:

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.

Создать шаблон:

rb-search init

Формат:

{
  "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/"
    }
  }
}

Управление:

rb-search list                 # показать серверы, default помечен *
rb-search set-default prod     # сменить default

Переменные окружения

Если конфиг-файла нет и заданы переменные — синтезируется сервер env, он же default:

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 в этом случае игнорируется, чтобы поведение было однозначным.

Использование

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/файлом.

Примеры

# Все сообщения как 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 обычная работа возобновится.