Этот репозиторий предлагает оптимизированный, полуавтоматический процесс создания gRPC мок-серверов. Инструмент берет на
себя рутинные задачи компиляции Protobuf — такие, как автоматическое исправление путей go_package и управление
зависимостями — и генерирует Go-код (заглушки), сохраняя при этом вашу кастомную бизнес-логику при обновлениях.
Детали генерации заглушек даны в описании работы утилиты upd-stubs.
.
├── Makefile # Главный оркестратор рабочего процесса
├── bin/ # Скомпилированные бинарные файлы
├── cmd/ # Точки входа (сервер и утилиты)
├── internal/
│ ├── app/ # Связывание приложения (DI)
│ ├── genproto/ # Сгенерированные .pb.go файлы (НЕ РЕДАКТИРОВАТЬ)
│ └── stubs/ # Реализации сервисов (<--- РЕДАКТИРУЙТЕ ЗАГЛУШКИ ЗДЕСЬ)
├── pkg/
│ ├── ctxkeys/ # Определения ключей контекста
│ ├── metrics/ # Сервер метрик Prometheus
│ ├── mgmt/ # Сервер управления для e2e-тестирования
│ └── recorder/ # Запись gRPC-вызовов
├── api-protos/ # <--- Поместите ваши .proto файлы сюда
└── scripts/ # Вспомогательные скрипты для исправления пакетов и генерации
- Go: версия 1.25 или выше
- Python: 3.x (для скрипта
update_go_packages.py) - Protoc: Компилятор Protocol Buffers (должен быть в системном PATH)
- Make
Скрипт gen-protos.sh попытается автоматически установить необходимые Go-плагины (protoc-gen-go,
protoc-gen-go-grpc), если они отсутствуют.
Рабочий процесс максимально упрощен:
- Скопируйте ваши
.protoфайлы в директориюapi-protos/. Вы можете сохранить существующую структуру папок ( например,api-protos/payment/v1/api.proto). - Запустите команду сборки:
make all
- Проверьте сгенерированные заглушки в папке
internal/stubs/.- Инструмент автоматически создаст структуры Go и сигнатуры методов.
- Вы можете реализовать логику мока внутри этих файлов. Будущие запуски не перезапишут ваш код; они лишь добавят новые методы, если изменится определение proto-файла.
- Запустите сервер:
./bin/grpc-mock run
- Автоматическое управление пакетами: Python-скрипт (
scripts/update_go_packages.py) сканирует директориюapi-protos/и автоматически внедряет или обновляет опциюgo_packageво всех файлах в соответствии со структурой проекта. Также рекурсивно исправляются локальные пути импорта. - Умная генерация заглушек: Утилита
upd-stubsгенерирует бойлерплейт для реализации сервера. Она использует парсинг Go AST, чтобы гарантировать, что существующая логика внутри методов сохранится при повторной генерации моков. - Поддержка скрытых папок: Директории, начинающиеся с точки (например,
api-protos/.private), автоматически игнорируются при генерации. - Внедрение зависимостей: Используется Google Wire для автоматического связывания новых сервисов с основным gRPC-сервером.
- Поддержка рефлексии (Reflection): Встроенная поддержка gRPC Reflection позволяет таким инструментам, как Postman или BloomRPC, динамически обнаруживать сервисы.
Сервер grpc-mock построен на базе фреймворка Cobra и стандартных библиотек Google gRPC.
- Внедрение зависимостей (Wire):
Приложение использует
google/wireв пакетеinternal/app. При запускеmake wire(илиmake all) инструмент обнаруживает новые заглушки вinternal/stubsи регистрирует их в функцииInitializeApp. - Перехватчики (Interceptors) и логирование:
Сервер включает глобальный
loggingInterceptor, который обрабатывает каждый запрос. Он генерирует уникальный Request ID, внедряет его в контекст и логирует статус запроса. - Ключи контекста:
Вы можете получить сгенерированный Request ID внутри ваших заглушек, используя хелпер из
pkg/ctxkeys. - Плавная остановка (Graceful Shutdown):
Сервер прослушивает системные сигналы (
SIGINT,SIGTERM) для корректного завершения соединений.
Управление сервером осуществляется через команду run. Конфигурацию можно передать через позиционные аргументы, флаги
или переменные окружения.
./bin/grpc-mock run [host] [port] [flags][host]: Интерфейс для привязки (например,127.0.0.1).[port]: Порт для прослушивания (например,50051).- Примечание: Позиционные аргументы имеют наивысший приоритет.
| Флаг | Сокр. | Описание |
|---|---|---|
--host |
Хост интерфейса (переопределяет переменную HOST). |
|
--port |
-p |
Порт (переопределяет переменную PORT). |
--mgmt-port |
-m |
Порт сервера управления (переопределяет MGMT_PORT). |
--metrics-port |
Порт сервера метрик (переопределяет METRICS_PORT). |
|
--mgmt-enabled |
Включить сервер управления (переопределяет MGMT_ENABLED). |
|
--metrics-enabled |
Включить сервер метрик (переопределяет METRICS_ENABLED). |
|
--logging |
Включить логирование gRPC запросов (переопределяет GRPC_LOGGING). |
|
--reflection |
-r |
Включить gRPC рефлексию (переопределяет GRPC_REFLECTION). |
--log-format |
Формат логов: json/console (переопределяет LOG_FORMAT). |
|
--log-output |
Куда писать логи: stdout/file (переопределяет LOG_OUTPUT). |
|
--log-file |
Путь до лог-файла при output=file (переопределяет LOG_FILE). |
|
--log-level |
Уровень логирования: debug..error (переопределяет LOG_LEVEL). |
|
--trace-enabled |
Включить OpenTelemetry tracing (переопределяет TRACE_ENABLED). |
|
--trace-exporter |
Экспортер трейсов: none/file/otlp-http (переопределяет TRACE_EXPORTER). |
|
--trace-endpoint |
OTLP HTTP endpoint, напр. otel-collector:4318 (переопределяет TRACE_ENDPOINT). |
|
--trace-file |
Файл трейсов при exporter=file (переопределяет TRACE_FILE). |
|
--trace-sampling-ratio |
Доля семплирования 0.0–1.0 (переопределяет TRACE_SAMPLING_RATIO). |
|
--request-id-headers |
Заголовки входящего request id через запятую (переопределяет REQUEST_ID_HEADERS). |
|
--request-id-response-header |
Каноничный response header (переопределяет REQUEST_ID_RESPONSE_HEADER). |
|
--no-mgmt |
(устаревший) Используйте --mgmt-enabled=false. |
|
--no-metrics |
(устаревший) Используйте --metrics-enabled=false. |
|
--no-logs |
(устаревший) Используйте --logging=false. |
|
--help |
-h |
Показать справку. |
Если флаги или аргументы не переданы, сервер использует значения из переменных окружения:
| Переменная | По умолч. | Описание |
|---|---|---|
HOST |
0.0.0.0 | Хост интерфейса для привязки |
PORT |
50051 | Порт для прослушивания |
MGMT_PORT |
9000 | Порт сервера управления |
METRICS_PORT |
9100 | Порт сервера метрик Prometheus |
MGMT_ENABLED |
true | Включить сервер управления |
METRICS_ENABLED |
true | Включить сервер метрик |
GRPC_REFLECTION |
false | Включить gRPC рефлексию |
GRPC_LOGGING |
true | Включить логирование запросов/ответов |
REQUEST_ID_HEADERS |
x-request-id,... | Заголовки для входящего request id (через запятую) |
REQUEST_ID_RESPONSE_HEADER |
x-request-id | Каноничный response header c request id |
LOG_FORMAT |
json | Формат логов (json/console) |
LOG_OUTPUT |
stdout | Куда писать логи (stdout/file) |
LOG_FILE |
- | Путь до лог-файла, если LOG_OUTPUT=file |
LOG_LEVEL |
info | Уровень логирования (debug..error) |
TRACE_ENABLED |
false | Включить OpenTelemetry tracing |
TRACE_EXPORTER |
none | Экспортер трейсов (none/file/otlp-http) |
TRACE_ENDPOINT |
- | OTLP HTTP endpoint (например otel-collector:4318) |
TRACE_FILE |
./traces.json | Файл трейсов при TRACE_EXPORTER=file |
TRACE_SAMPLING_RATIO |
1.0 | Доля семплирования трейсов |
# Запуск с настройками по умолчанию (0.0.0.0:50051)
./bin/grpc-mock run
# Запуск на порту 50051 с включенной рефлексией
./bin/grpc-mock run -p 50051 -r
# Запуск только на localhost, логирование отключено
./bin/grpc-mock run 127.0.0.1 50051 --no-logs
# Запуск без сервера управления
./bin/grpc-mock run --no-mgmtДля поддержки e2e-тестирования gRPC-мок включает встроенный HTTP-сервер управления на порту 9000 (по умолчанию). Этот сервер записывает все gRPC-вызовы и предоставляет API для их просмотра и очистки.
| Метод | Путь | Описание |
|---|---|---|
GET |
/logs |
Получить все записанные gRPC-вызовы в формате JSON |
GET |
/logs/{request_id} |
Получить записи для конкретного request id |
DELETE |
/logs |
Очистить все записи |
POST |
/reset |
Soft reset (очистка записей + сброс состояния) |
GET |
/docs |
Список зарегистрированных gRPC-сервисов |
GET |
/docs/{service} |
Методы конкретного gRPC-сервиса |
GET |
/doc |
Интерактивная страница Swagger UI |
GET |
/openapi.json |
Спецификация OpenAPI в формате JSON |
| Метод | Путь | Описание |
|---|---|---|
GET |
/context-values |
Получить все контекстные значения |
PUT |
/context-values |
Заменить все контекстные значения |
PATCH |
/context-values |
Объединить с существующими контекстными значениями |
DELETE |
/context-values |
Очистить все контекстные значения |
GET |
/context-values/{request_id} |
Получить значения для конкретного request id |
PUT |
/context-values/{request_id} |
Заменить значения для конкретного request id |
PATCH |
/context-values/{request_id} |
Объединить значения для конкретного request id |
DELETE |
/context-values/{request_id} |
Удалить значения для конкретного request id |
{
"request_id": "ABCD1234",
"method": "/EchoService/Echo",
"timestamp": "2026-02-10T12:00:00Z",
"request": {
"message": "Привет"
},
"response": {
"message": "Привет"
},
"error": "",
"panic": "",
"duration_ms": 5
}- Запись запросов и ответов: Полные тела запросов и ответов сохраняются в памяти.
- Фильтрация по request_id: Получение записей для конкретного идентификатора запроса через
GET /logs/{request_id}. - Отслеживание ошибок: Если gRPC-метод вернул ошибку, она будет записана в поле
error. - Отслеживание паник: Если в обработчике произошла паника, она будет записана в поле
panic. - Временные метки: Каждый вызов содержит timestamp и duration_ms.
- Soft reset:
POST /resetочищает все записи и сбрасывает состояние мок-сервера без остановки процесса. - Swagger UI: Встроенная интерактивная документация (файлы загружены в бинарник, не требуют сети).
# Получить все записанные вызовы
curl http://localhost:9000/logs
# Получить записи для конкретного request id
curl http://localhost:9000/logs/ABCD1234
# Очистить записи
curl -X DELETE http://localhost:9000/logs
# Soft reset (очистка записей + сброс состояния)
curl -X POST http://localhost:9000/reset
# Открыть Swagger UI в браузере
open http://localhost:9000/docДля мониторинга и observability gRPC-мок включает встроенный HTTP-сервер метрик на порту 9100 (по умолчанию,
переопределяется METRICS_PORT). Метрики экспортируются в формате Prometheus и доступны по эндпоинту /metrics.
| Метод | Путь | Описание |
|---|---|---|
GET |
/metrics |
Метрики в формате Prometheus text/plain |
| Метрика | Тип | Labels | Описание |
|---|---|---|---|
grpc_requests_total |
Counter | method, status |
Общее количество gRPC запросов (для RPS) |
grpc_request_duration_seconds |
Histogram | method, status |
Гистограмма латентности запросов |
grpc_errors_total |
Counter | method, kind |
Количество ошибок по типу (error rate) |
grpc_panics_total |
Counter | method, kind |
Количество паник по типу (panic rate) |
grpc_requests_in_flight |
Gauge | method |
Количество обрабатываемых запросов |
| Метрика | Тип | Labels | Описание |
|---|---|---|---|
grpc_memory_bytes |
Gauge | type |
Использование памяти (alloc, heap, sys, stack) |
grpc_goroutines_total |
Gauge | — | Количество горутин |
go_memstats_* |
— | — | Детальная статистика Go runtime (GC, heap и т.д.) |
process_cpu_seconds_total |
Counter | — | Время CPU (user + system) |
process_resident_memory_bytes |
Gauge | — | Резидентная память процесса |
# Получить все метрики
curl http://localhost:9100/metrics
# Получить только gRPC метрики
curl -s http://localhost:9100/metrics | grep "^grpc_"
# Получить метрики памяти
curl -s http://localhost:9100/metrics | grep "process_resident_memory"Добавьте в ваш prometheus.yml:
scrape_configs:
- job_name: 'grpc-mock'
static_configs:
- targets: [ 'localhost:9100' ]
scrape_interval: 15s# RPS по методам
rate(grpc_requests_total[1m])
# Средняя латентность (p50)
histogram_quantile(0.5, rate(grpc_request_duration_seconds_bucket[5m]))
# Латентность p99
histogram_quantile(0.99, rate(grpc_request_duration_seconds_bucket[5m]))
# Error rate
rate(grpc_errors_total[1m])
# Память heap
grpc_memory_bytes{type="heap_alloc"}
При включении флага TRACE_ENABLED=true (по умолчанию выключено) сервер автоматически извлекает traceparent из
метаданных gRPC-запросов и отправляет спаны в OpenTelemetry Collector.
Поддерживаемые экспортеры:
| Экспортер | Описание | Переменные |
|---|---|---|
none |
Трассировка отключена (по умолчанию) | — |
file |
Запись спанов в JSON-файл (удобно для отладки) | TRACE_FILE |
otlp-http |
Отправка спанов через OTLP HTTP в Collector/Tempo | TRACE_ENDPOINT, TRACE_FILE |
# Пример запуска с файловым экспортером
TRACE_ENABLED=true TRACE_EXPORTER=file ./bin/grpc-mock run
# Пример запуска с OTLP HTTP экспортером
TRACE_ENABLED=true TRACE_EXPORTER=otlp-http TRACE_ENDPOINT=otel-collector:4318 ./bin/grpc-mock run
# Пример запроса с пробросом конкретного trace_id через grpcurl
grpcurl -plaintext \
-H 'traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01' \
-d '{"message":"traced"}' \
localhost:50051 EchoService/EchoВсе логи gRPC-запросов и внутреннее логирование автоматически связываются с request_id, trace_id и method.
Формат логов по умолчанию — json (управляется переменной LOG_FORMAT), что делает их готовыми для парсинга и
отправки в Loki. В заглушках (stubs) рекомендуется использовать контекстный логгер из pkg/observability для
сохранения привязки к trace_id:
logger := observability.Logger(ctx, zerolog.Nop())
logger.Info().Msg("Запрос достиг бизнес-логики") // Будет содержать trace_id и methodПри запуске команды make all выполняются следующие шаги:
make update-proto-pkg:- Проходит по директории
api-protos/. - Вычисляет правильный путь импорта Go на основе структуры папок (например,
api-protos/echoпревращается вgrpc-mock/internal/genproto/echo). - Обновляет
go_packageв.protoфайлах и исправляет относительные импорты.
- Проходит по директории
make proto:- Компилирует
.protoфайлы с помощьюprotocв директориюinternal/genproto. - Примечание: Папки, начинающиеся с точки (например,
api-protos/.hidden), пропускаются.
- Компилирует
make stub:- Собирает и запускает кастомную утилиту
upd-stubs. - Сканирует
internal/genprotoна наличие определений сервисов. - Создает новые или обновляет существующие файлы реализации в
internal/stubs.
- Собирает и запускает кастомную утилиту
make wire:- Регенерирует
internal/app/wire_gen.go, чтобы зарегистрировать новые заглушки в gRPC-сервере.
- Регенерирует
make build:- Компилирует финальный бинарный файл
bin/grpc-mock.
- Компилирует финальный бинарный файл
Проект поддерживает работу через Docker, которая избавляет от необходимости устанавливать Go, Protoc или Python на локальную машину.
Используется конфигурация docker-compose с этапом dev. В этом режиме:
Запуск:
make docker-dev
# или
docker compose -f docker-compose.dev.yaml up --buildРабочий процесс:
- Исходный код с хоста пробрасывается в контейнер (volume mapping).
- Контейнер собирает и запускает сервер.
- Для применения изменений: остановите контейнер (
Ctrl+C) и перезапустите (make docker-dev). - Сгенерированные файлы (например,
.pb.goили новые заглушки) появляются на вашей локальной машине, обеспечивая работу автодополнения в IDE.
Для запуска стека мониторинга (доступен по адресу http://localhost:3000):
make compose-upДля просмотра логов:
make compose-logsДля остановки:
make compose-downДля smoke-тестирования:
make compose-smokeCompose-файлы:
docker-compose.dev.yaml— dev-окружение.docker-compose.observability.yaml— полный observability-стек (Prometheus, Loki, Tempo, OTel Collector, Grafana).- Конфиги сервисов лежат в
deploy/(prometheus.yaml,otel.yaml,promtail.yaml,tempo.yaml,grafana/).
Рекомендуемое место для локальных overrides — корневой
.env(напримерcp .env.example .env).make docker-devиmake compose-*автоматически передадут его в Docker Compose. Для обратной совместимости также поддерживаетсяdeploy/.env.
Для создания легковесного, готового к деплою Docker-образа используется многоэтапная сборка (multistage build). Финальный образ базируется на Alpine Linux и содержит только скомпилированный бинарный файл.
Сборка:
make docker-build
# или
docker build -t grpc-mock:latest .Запуск:
make docker-run
# или
docker run --rm -p 50051:50051 -p 9000:9000 -p 9100:9100 grpc-mock:latestСтруктура Dockerfile:
- Stage
tools: Базовый образ с предустановленными компиляторами (protoc, python, go) и скомпилированной утилитойupd-stubs. - Stage
dev: Наследуется отtools, собирает и запускает сервер. Используется в docker-compose. - Stage
builder: Выполняет полную сборку проекта (make all) для релиза. - Stage
production: Минимальный образ, содержащий только результат работыbuilder.