go mod init github.com/moguchev/gofunc_autumn_2024
mkdir -p proto/api/example
- Создаем
service.proto
иmessage.proto
в./proto/api/example/v1
:touch ./proto/api/example/v1/service.proto
touch ./proto/api/example/v1/message.proto
- Описываем protobuf схему нашего сервиса
- Устанавливаем Buf
go install github.com/bufbuild/buf/cmd/buf@v1.36.0
buf --version
- Инициализируем конфиг Buf
buf config init
- создастся файлbuf.yaml
- Указываем путь до наших protobuf фалйов в buf.yaml:
modules:
- path: proto
- Создадим конфигурацию
buf.gen.yaml
для генерации кодаtouch buf.gen.yaml
- Указываем необходимые плагины для генерации go кода (см buf.gen.yaml)
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
- для генерации структур из gRPC сообщенийgo install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
- для генерации gRPC сервера и клиентаgo install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
- для генерации gRPC-Gateway proxygo install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest
- для генерации swagger спецификации
- Указыаемыем зависимости из Buf Schema Registry (BSR) в
buf.yaml
deps:
- buf.build/googleapis/googleapis
- buf.build/grpc-ecosystem/grpc-gateway
- buf.build/bufbuild/protovalidate
buf dep update
- создаст файлbuf.lock
- Вручную (или с помощью скриптов) скачиваем необходимые protobuf файлы и складываем в директорию
vendor.proto
make vendor
- в нашем примере написан Makefilevendor.proto.mk
, в котором происходит вендоринг необходимых protobuf файлов
- Указываем путь до скаченных protobuf файлов в
buf.yaml
modules:
- path: proto
- path: vendor.protobuf
buf build
- проверяем, что все необходимые зависимости корректно установленыbuf genereate
- генерация golang кода
buf format -w
- запуск форматирования
- Установите расширение Buf
- Выберете Buf в качестве форматера по умолчанию:
⌘ + Shift + P
->Fromat Document
->Configure Default Formatter
- Добавьте следующие настройки в
settings.json
файл для форматирования protobuf файлов при сохранении:
"[proto]": {
"editor.formatOnSave": true
}
- Настраиваем правила для линтера
- Linting Overview
- Rules and Categories
- В
buf.yaml
указываем необходимые нам настройки
lint: use: - STANDARD - COMMENTS
- В случае вендоринга сторонних protobuf файлов вручную, стоит указать их в разделе
ignore
(не всегда работает)
lint: use: - STANDARD - COMMENTS ignore: - vendor.protobuf
buf lint -v
- запуск линтера
go get github.com/rookie-ninja/rk-grpc/v2
- устанавливаем rk-grpc- Создайте в корне проекта файл
boot.yaml
- конфигурация для rk-boot
grpc:
- name: example # Название нашего entry
description: "example server"
enabled: true # Можем отключить entry при необходимости (мало ли ...)
port: 82 # Порт на котором будем принимать входящие gRPC запросы
enableReflection: true # Включить gRPC reflection (в основном нужно для grpcurl, grpcli, postman)
gwPort: 80 # Порт на котором будем принимать входящие HTTP запросы в gRPC-Gateway
gwOption: # Настройки опций gRPC-Gateway
marshal: # https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson#MarshalOptions
multiline: false
emitUnpopulated: true
indent: ""
allowPartial: false
useProtoNames: false
useEnumNumbers: false
unmarshal: # https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson#UnmarshalOptions
allowPartial: false
discardUnknown: true
- Создайте в корне проекта файл
config.go
package config
import (
_ "embed"
)
//go:embed boot.yaml
var Boot []byte
- Создайте
main.go
в директорииcmd/example
:
package main
import (
"context"
"log"
config "github.com/moguchev/gofunc_autumn_2024"
examplev1 "github.com/moguchev/gofunc_autumn_2024/internal/app/api/example/v1"
pb "github.com/moguchev/gofunc_autumn_2024/pkg/api/example/v1"
rkboot "github.com/rookie-ninja/rk-boot/v2"
rkgrpc "github.com/rookie-ninja/rk-grpc/v2/boot"
"google.golang.org/grpc"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Инициализация нашего RPC обработчика
srv, err := examplev1.NewExampleServiceServerImplementation()
if err != nil {
log.Fatalf("couldn't create server: %v", err)
}
// Загрузжаем entries из конфигурации (boot.yaml).
boot := rkboot.NewBoot(
rkboot.WithBootConfigRaw(config.Boot),
)
// Получение GrpcEntry
grpcEntry := rkgrpc.GetGrpcEntry("example") // название entry
// Регистрация gRPC сервера
grpcEntry.AddRegFuncGrpc(func(server *grpc.Server) { pb.RegisterExampleServiceServer(server, srv) })
// Регистрация gRPC-Gateway proxy
grpcEntry.AddRegFuncGw(pb.RegisterExampleServiceHandlerFromEndpoint)
// Bootstrap entry
boot.Bootstrap(ctx)
// Ждем сигнала выключения
boot.WaitForShutdownSig(ctx)
}
go run ./cmd/example
- запуск сервиса
2024-09-15T15:57:03.400+0300 INFO boot/grpc_entry.go:1060 Bootstrap grpcEntry {"eventId": "c60f8189-d910-491b-b938-4ac59cfe422c", "entryName": "example", "entryType": "gRPCEntry"}
2024-09-15T15:57:03.400+0300 INFO boot/grpc_entry.go:761 gRPC_port:82
2024-09-15T15:57:03.400+0300 INFO boot/grpc_entry.go:762 gateway_port:80
- Добавим в
boot.yaml
у нашего gRPC entryexample
следующий конфиг:
commonService: # Swagger UI клиент для RK сервиса
enabled: true
sw: # Swagger UI клиент: https://github.com/swagger-api/swagger-ui
enabled: true
path: "swagger"
jsonPaths:
- swagger
headers: []
docs: # Встроенный экземпляр RapiDoc https://github.com/rapi-doc/RapiDoc, который можно использовать вместо Swagger
enabled: true
path: "docs"
specPath: "swagger"
headers: []
style:
theme: "light"
debug: true
go run ./cmd/example
- запуск сервиса
2024-09-15T16:08:42.262+0300 INFO boot/grpc_entry.go:1060 Bootstrap grpcEntry {"eventId": "a636bbf6-afd0-4b06-80e8-0f0f87951e44", "entryName": "example", "entryType": "gRPCEntry"}
2024-09-15T16:08:42.262+0300 INFO boot/grpc_entry.go:761 gRPC_port:82
2024-09-15T16:08:42.262+0300 INFO boot/grpc_entry.go:762 gateway_port:80
2024-09-15T16:08:42.262+0300 INFO boot/grpc_entry.go:765 SwaggerEntry: http://localhost:80/swagger/
2024-09-15T16:08:42.262+0300 INFO boot/grpc_entry.go:768 DocsEntry: http://localhost:80/docs/
2024-09-15T16:08:42.262+0300 INFO boot/grpc_entry.go:783 CommonSreviceEntry: http://localhost:80/rk/v1/ready, http://localhost:80/rk/v1/alive, http://localhost:80/rk/v1/info
- Добавим в
boot.yaml
у нашего gRPC entryexample
следующий конфиг:
prom: # Prometheus client will automatically register into grpc-gateway instance at /metrics.
enabled: true
middleware:
prom: # метрики
enabled: true
go run ./cmd/example
- запуск сервиса- http://localhost/metrics - endpoint для сбора метрик
- Добавим в
boot.yaml
у нашего gRPC entryexample
следующий конфиг:
pprof: # Профилирование
enabled: true
path: "/pprof"
go run ./cmd/example
- запуск сервиса- http://localhost/pprof - endpoint pprof
- Добавим в
boot.yaml
у нашего gRPC entryexample
следующий конфиг для логирования запросов:
middleware:
logging: # логирование https://github.com/rookie-ninja/rk-query
enabled: true
ignore: [""]
loggerEncoding: "json" # console, json, flatten
loggerOutputPaths: ["stdout"]
eventEncoding: "json" # console, json, flatten
eventOutputPaths: ["stdout"]
- Добавим в
boot.yaml
у нашего gRPC entryexample
следующий конфиг для настройки глобального логирования:
logger: # logging with [rk-logger](https://github.com/rookie-ninja/rk-logger)
- name: zap
description: "ZAP"
domain: "*"
default: true
zap:
level: debug
development: true
disableCaller: false
disableStacktrace: true
encoding: json # console, json, flatten
outputPaths: ["stdout"]
errorOutputPaths: ["stderr"]
encoderConfig:
timeKey: "ts"
levelKey: "level"
nameKey: "logger"
callerKey: "caller"
messageKey: "msg"
stacktraceKey: "stacktrace"
skipLineEnding: false
lineEnding: "\n"
consoleSeparator: "\t"
sampling: # Optional, default: nil
initial: 0
thereafter: 0
initialFields:
key: value
event: # logging of RPC with [rk-query](https://github.com/rookie-ninja/rk-query)
- name: event
description: "event entry"
domain: "*"
encoding: json # console, json, flatten
default: true
outputPaths: ["stdout"]
- Добавим в
boot.yaml
у нашего gRPC entryexample
следующий конфиг:
middleware:
trace: # Трейсинг
enabled: true
ignore: [""]
exporter:
file:
enabled: true
outputPath: "logs/trace.log"
jaeger:
agent:
enabled: false
host: "localhost"
port: 6831
collector:
enabled: false
endpoint: "http://localhost:14268/api/traces"
username: ""
password: ""