From 3e999f8b6060fe944535b70a092a95b83bbf9e6e Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Sun, 25 Aug 2024 16:45:27 +0300 Subject: [PATCH] added metrics, fix charsets --- src/charsets/enum.go | 2 +- src/core/services/user_service.go | 2 +- src/integrations/prometheus.go | 79 ++++++++++++++++++++++++++++ src/logger/bufio_wrapper.go | 5 +- src/server/middleware/recovery.go | 5 +- src/server/middleware/request_log.go | 8 ++- src/server/server.go | 8 ++- 7 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 src/integrations/prometheus.go diff --git a/src/charsets/enum.go b/src/charsets/enum.go index 42b58d7..2fef2d8 100644 --- a/src/charsets/enum.go +++ b/src/charsets/enum.go @@ -25,7 +25,7 @@ func GetCharset(charsetType CharsetType) Charset { case CharsetTypeLettersLower: return charsetLettersLower case CharsetTypeLettersUpper: - return charsetLettersLower + return charsetLettersUpper case CharsetTypeLetters: return charsetLetters case CharsetTypeAll: diff --git a/src/core/services/user_service.go b/src/core/services/user_service.go index 3faf7fe..8d8a3da 100644 --- a/src/core/services/user_service.go +++ b/src/core/services/user_service.go @@ -58,7 +58,7 @@ func (u *userService) CreateUser(ctx context.Context, params UserCreateParams) ( } if err := u.deps.Password.Validate(params.Password); err != nil { - return nil, ErrUserBadPassword + return nil, err } secret, err := u.deps.Password.Hash(params.Password) diff --git a/src/integrations/prometheus.go b/src/integrations/prometheus.go new file mode 100644 index 0000000..d30b8cb --- /dev/null +++ b/src/integrations/prometheus.go @@ -0,0 +1,79 @@ +package integrations + +import ( + "net/http" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +type Prometheus struct { + reg *prometheus.Registry + rpsGauge prometheus.Gauge + avgReqTimeHist prometheus.Histogram + panicsHist prometheus.Histogram +} + +func NewPrometheus() *Prometheus { + reg := prometheus.NewRegistry() + + // Add go runtime metrics and process collectors. + reg.MustRegister( + collectors.NewGoCollector(), + collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}), + ) + + // errorsCounter := prometheus.NewCounter( + // prometheus.CounterOpts{ + // Name: "backend_errors_count", + // Help: "Summary errors count", + // }, + // ) + rpsGauge := prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "backend_requests_per_second", + Help: "Requests per second metric", + }, + ) + avgReqTimeHist := prometheus.NewHistogram( + prometheus.HistogramOpts{ + Name: "backend_requests_average_time", + Help: "Average time of requests", + }, + ) + panicsHist := prometheus.NewHistogram( + prometheus.HistogramOpts{ + Name: "backend_panics", + Help: "Panics histogram metric", + }, + ) + reg.MustRegister(rpsGauge, avgReqTimeHist, panicsHist) + + return &Prometheus{ + panicsHist: panicsHist, + avgReqTimeHist: avgReqTimeHist, + rpsGauge: rpsGauge, + reg: reg, + } +} + +func (p *Prometheus) GetRequestHandler() http.Handler { + return promhttp.HandlerFor(p.reg, promhttp.HandlerOpts{Registry: p.reg}) +} + +func (p *Prometheus) RequestInc() { + p.rpsGauge.Inc() +} + +func (p *Prometheus) RequestDec() { + p.rpsGauge.Dec() +} + +func (p *Prometheus) AddRequestTime(reqTime float64) { + p.avgReqTimeHist.Observe(reqTime) +} + +func (p *Prometheus) AddPanic() { + p.panicsHist.Observe(1) +} diff --git a/src/logger/bufio_wrapper.go b/src/logger/bufio_wrapper.go index 8156cd2..a87f63d 100644 --- a/src/logger/bufio_wrapper.go +++ b/src/logger/bufio_wrapper.go @@ -26,5 +26,8 @@ func (b *bufioWrapper) Flush() error { } func (b *bufioWrapper) Close() error { - return b.Flush() + b.m.Lock() + defer b.m.Unlock() + + return b.Writer.Flush() } diff --git a/src/server/middleware/recovery.go b/src/server/middleware/recovery.go index 016bc62..798c74c 100644 --- a/src/server/middleware/recovery.go +++ b/src/server/middleware/recovery.go @@ -3,6 +3,7 @@ package middleware // Modified recovery from gin, use own logger import ( + "backend/src/integrations" "backend/src/logger" "bytes" "errors" @@ -29,11 +30,13 @@ var ( slash = []byte("/") ) -func NewRecoveryMiddleware(logger logger.Logger, debugMode bool) gin.HandlerFunc { +func NewRecoveryMiddleware(logger logger.Logger, prometheus *integrations.Prometheus, debugMode bool) gin.HandlerFunc { handle := defaultHandleRecovery return func(c *gin.Context) { defer func() { if err := recover(); err != nil { + prometheus.AddPanic() + // Check for a broken connection, as it is not really a // condition that warrants a panic stack trace. var brokenPipe bool diff --git a/src/server/middleware/request_log.go b/src/server/middleware/request_log.go index 691bc33..726d30c 100644 --- a/src/server/middleware/request_log.go +++ b/src/server/middleware/request_log.go @@ -1,6 +1,7 @@ package middleware import ( + "backend/src/integrations" log "backend/src/logger" "time" @@ -8,8 +9,11 @@ import ( "github.com/google/uuid" ) -func NewRequestLogMiddleware(logger log.Logger) gin.HandlerFunc { +func NewRequestLogMiddleware(logger log.Logger, prometheus *integrations.Prometheus) gin.HandlerFunc { return func(c *gin.Context) { + prometheus.RequestInc() + defer prometheus.RequestDec() + requestId := c.GetHeader("X-Request-Id") if requestId == "" { requestId = uuid.New().String() @@ -26,6 +30,8 @@ func NewRequestLogMiddleware(logger log.Logger) gin.HandlerFunc { c.Next() latency := time.Since(start) + prometheus.AddRequestTime(float64(latency)) + method := c.Request.Method statusCode := c.Writer.Status() clientIP := c.ClientIP() diff --git a/src/server/server.go b/src/server/server.go index 3d0ad53..ce73c6b 100644 --- a/src/server/server.go +++ b/src/server/server.go @@ -3,6 +3,7 @@ package server import ( "backend/src/client_notifier" "backend/src/core/services" + "backend/src/integrations" "backend/src/logger" "backend/src/server/handlers" "backend/src/server/middleware" @@ -35,8 +36,11 @@ func New(opts NewServerOpts) *Server { r.Static("/webapp", "./webapp") r.GET("/health", handlers.NewDummyHandler()) - r.Use(middleware.NewRequestLogMiddleware(opts.Logger)) - r.Use(middleware.NewRecoveryMiddleware(opts.Logger, opts.DebugMode)) + prometheus := integrations.NewPrometheus() + r.Any("/metrics", gin.WrapH(prometheus.GetRequestHandler())) + + r.Use(middleware.NewRequestLogMiddleware(opts.Logger, prometheus)) + r.Use(middleware.NewRecoveryMiddleware(opts.Logger, prometheus, opts.DebugMode)) r.GET("/pooling", handlers.NewLongPoolingHandler(opts.Logger, opts.Notifier))