func main() {
logger, _ := zap.NewProduction()
undo := zap.ReplaceGlobals(logger)
server.Run(logger, undo)
}
Вызов записи лога в stdout
zap.L().Error("Ошибка...", zap.Error(err))
Отображение лога
{"level":"info","ts":1667409039.5448234,"caller":"config/initConfig.go:41","msg":"Config = ",
"cfg":{"Address":"localhost:8081","DSN":"user=dbuser password=xxx dbname=accrual sslmode=disable",
"Accrual":"localhost:8080"}}
Почему именно Gin:
- Логика работы понятна и проста,
- Локаничный код,
- Пригодились в проекте расширения функционала gzip, pprof (github.com/gin-contrib)
- Синтаксический сахар
c.Status(), c.JSON()
и т.д.*жестокие эксперименты над кодом с возможным летальным исходом последнего...
- Получить степень живучести кода, т.е. при каких максимальных нагрузках выдаётся (с вероятностью в 100%) ожидаемый результат,
- Получить конкретную величину краткосрочной пиковой нагрузки на имеющемся "железе" условного заказчика проекта,
- Получить кривую отношения величины нагрузки к проценту выдаваемых ошибок проекта.
- Поиск варианта для нагрузочного тестирования (собственные тесты, плагины/утилиты, программные продукты),
- Поиск варианта отслеживания таймингов выполнения каждой строчки кода (собственные тесты, плагины/утилиты, программные продукты),
- По результатам тестирования - оптимизация кода (логгирование, проверки данных, запросы к БД и т.д.)
Варианты нагрузочного тестирования | Порог входа | Нагрузка на железо | Скорость работы |
---|---|---|---|
go-wrk | |||
Собственные тесты | |||
Postman | |||
Яндекс.Танк, JMeter и другие | No comments | ||
Grafana K6 |
Утилита PPROF
ROUTINE ======================== github.com/etitovets/diploma_team/internal/accrual/handlers.(*Handler).AddGoods in
c:\golang\github.com\etitovets\diploma_team\internal\accrual\handlers\addgoods.go
30ms 6.26s (flat, cum) 32.40% of Total
. . 8: "github.com/etitovets/diploma_team/internal/accrual/model"
. . 9: "github.com/gin-gonic/gin"
. . 10: "go.uber.org/zap"
. . 11:)
. . 12:
10ms 10ms 13:func (h *Handler) AddGoods(c *gin.Context) {
. 280ms 14: body, err := h.GetBodyWithGZIPCheck(c)
. . 15: if err != nil {
. . 16: zap.L().Error("Ошибка GetBodyWithGZIPCheck", zap.Error(err))
. . 17: c.JSON(http.StatusInternalServerError, err.Error())
. . 18: return
. . 19: }
. . 20:
. . 21: newGoods := model.NewGoods{}
. 730ms 22: if err := json.Unmarshal(body, &newGoods); err != nil {
. . 23: c.JSON(http.StatusBadRequest, "JSON is not correct")
. . 24: return
. . 25: }
. . 26:
10ms 20ms 27: err = h.ValidatingGoods(newGoods)
. . 28: if err != nil {
. . 29: zap.L().Error("Ошибка ValidateGoods", zap.Error(err))
. . 30: c.JSON(http.StatusBadRequest, err.Error())
. . 31: return
. . 32: }
. . 33:
. 5.20s 34: err = h.serv.AddGoods(newGoods)
. . 35: if err != nil {
. . 36: if errors.Is(err, model.ErrUniqueMatch) {
10ms 20ms 37: c.Status(http.StatusConflict)
. . 38: return
. . 39: }
. . 40: c.JSON(http.StatusInternalServerError, err.Error())
. . 41: return
. . 42: }
ROUTINE ======================== github.com/etitovets/diploma_team/internal/accrual/storage.(*DBStorage).AddGoods in
c:\golang\github.com\etitovets\diploma_team\internal\accrual\storage\addgoods.go
10ms 5.20s (flat, cum) 26.92% of Total
. . 34: if err := tx.Commit(); err != nil {
. . 35: zap.L().Error("Ошибка tx.Commit", zap.Error(err))
. . 36: return err
. . 37: } */
. . 38:
. 4.78s 39: if _, err := d.db.Exec("INSERT INTO reward (match, reward, reward_type) VALUES ($1, $2, $3)",
. . 40: goods.Match,
. 20ms 41: goods.Reward,
. 10ms 42: goods.RewardType); err != nil {
. . 43: if err.(*pq.Error).Code == model.ErrCodeSQLUniqueOrder {
. 200ms 44: zap.L().Error("Ошибка Unique", zap.Error(err))
. . 45: return model.ErrUniqueMatch
. . 46: }
. . 47: zap.L().Error("Ошибка tx.Stmt", zap.Error(err))
10ms 10ms 48: return err
. . 49: }
. 180ms 50: zap.L().Info("Вознаграждение добавлено в БД!", zap.String("goods", goods.Match))
. . 51: return nil
. . 52:}
RAM: DDR4 32Gb (4х канальный режим)
SSD: m2 PCI-E 512Gb