Skip to content

Commit

Permalink
feat: add prometheus metric
Browse files Browse the repository at this point in the history
  • Loading branch information
fatihkahveci committed Jun 23, 2023
1 parent c076bbb commit d700be3
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 18 deletions.
4 changes: 3 additions & 1 deletion .env-example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ HTTP_PORT=80
STORGE=inmemory
SSL_CERT=""
SSL_KEY=""
SERVER_DIRTY_SECONDS=30
SERVER_DIRTY_SECONDS=30
PROMETHEUS_PORT=8080
PROMETHEUS_ENABLED=true
15 changes: 10 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,34 @@ require (
github.com/gofiber/fiber/v2 v2.44.0
github.com/google/uuid v1.3.0
github.com/joho/godotenv v1.5.1
github.com/stretchr/testify v1.8.2
github.com/prometheus/client_golang v1.16.0
)

require (
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/klauspost/compress v1.16.3 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/philhofer/fwd v1.1.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
github.com/tinylib/msgp v1.1.8 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.45.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/sys v0.8.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
32 changes: 29 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -11,6 +15,13 @@ github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp
github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig=
github.com/gofiber/fiber/v2 v2.44.0 h1:Z90bEvPcJM5GFJnu1py0E1ojoerkyew3iiNJ78MQCM8=
github.com/gofiber/fiber/v2 v2.44.0/go.mod h1:VTMtb/au8g01iqvHyaCzftuM/xmZgKOZCtFzz6CdV9w=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
Expand All @@ -26,11 +37,21 @@ github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp9
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4=
Expand Down Expand Up @@ -69,6 +90,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -83,8 +105,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
Expand All @@ -99,8 +121,12 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
Expand Down
47 changes: 44 additions & 3 deletions internal/server/http/fiber.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"game-server-selector/internal/models"
"game-server-selector/internal/services"
"game-server-selector/internal/validator"
"strconv"
"time"

"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
Expand All @@ -15,20 +17,30 @@ type FiberServer struct {
app *fiber.App
serverDomain domain.ServerDomain
configService services.ConfigService
metricService services.MetricService
}

func NewFiberServer(s domain.ServerDomain, c services.ConfigService) *FiberServer {
func NewFiberServer(
s domain.ServerDomain,
c services.ConfigService,
m services.MetricService,
) *FiberServer {
app := fiber.New()
app.Use(recover.New())
app.Use(logger.New())

return &FiberServer{
app: app,
serverDomain: s,
configService: c,
metricService: m,
}
}

func (s *FiberServer) InitMiddleware() {
s.app.Use(recover.New())
s.app.Use(logger.New())
s.app.Use(s.metricMiddleware)
}

func (s *FiberServer) Router() error {
v1 := s.app.Group("/v1")
v1.Get("/server/list", s.serverList)
Expand All @@ -45,7 +57,9 @@ func (s *FiberServer) Stop() error {
}

func (s *FiberServer) Start() error {
s.InitMiddleware()
s.Router()

port := s.configService.GetHttpPort()
certPath := s.configService.GetSslCertPath()
keyPath := s.configService.GetSslKeyPath()
Expand Down Expand Up @@ -125,3 +139,30 @@ func (s *FiberServer) serverUpdate(ctx *fiber.Ctx) error {
"server": server,
})
}

func (s *FiberServer) metricMiddleware(ctx *fiber.Ctx) error {
start := time.Now()
method := ctx.Route().Method
err := ctx.Next()
status := fiber.StatusInternalServerError

if ctx.Route().Path == "metrics" {
return ctx.Next()
}

if err != nil {
if e, ok := err.(*fiber.Error); ok {
status = e.Code
}
} else {
status = ctx.Response().StatusCode()
}

handler := ctx.Route().Path
statusCode := strconv.Itoa(status)
s.metricService.IncRequestTotal(handler, statusCode, method)
elapsed := float64(time.Since(start).Nanoseconds()) / 1e9
s.metricService.ObserveRequestDuration(handler, statusCode, method, elapsed)

return err
}
14 changes: 14 additions & 0 deletions internal/services/config_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ type ConfigService interface {
GetSslCertPath() string
GetSslKeyPath() string
GetServerDirtySeconds() int
GetPrometheusPort() string
IsPrometheusEnabled() bool
}

type configService struct{}
Expand Down Expand Up @@ -46,6 +48,18 @@ func (c *configService) GetServerDirtySeconds() int {
return c.getEnvInt("SERVER_DIRTY_SECONDS", 60)
}

func (c *configService) GetPrometheusPort() string {
return ":" + c.getEnv("PROMETHEUS_PORT", "8080")
}

func (c *configService) IsPrometheusEnabled() bool {
isEnabled := c.getEnv("PROMETHEUS_ENABLED", "false")
if isEnabled == "true" {
return true
}
return false
}

func (c *configService) getEnv(key string, fallback string) string {
env := os.Getenv(key)
if env != "" {
Expand Down
79 changes: 79 additions & 0 deletions internal/services/metric_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package services

import (
"net/http"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
requestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "Histogram of latencies for HTTP requests.",
Buckets: prometheus.DefBuckets,
},
[]string{"handler", "code", "method"},
)
requestTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_request_total",
Help: "Total number of HTTP requests made.",
}, []string{"handler", "code", "method"})

serverCount = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "server_count",
Help: "Count of game server",
}, []string{})
)

type MetricService interface {
Register()
Handler() http.Handler
IncServerCount()
DecServerCount()
ObserveRequestDuration(handler, code, method string, duration float64)
IncRequestTotal(handler, code, method string)
}

type metricService struct {
requestDuration *prometheus.HistogramVec
requestTotal *prometheus.CounterVec
serverCount *prometheus.GaugeVec
}

func NewMetricService() MetricService {
return &metricService{
requestDuration: requestDuration,
requestTotal: requestTotal,
serverCount: serverCount,
}
}

func (s *metricService) Register() {
prometheus.MustRegister(s.requestDuration)
prometheus.MustRegister(s.requestTotal)
prometheus.MustRegister(s.serverCount)
}

func (s *metricService) Handler() http.Handler {
return promhttp.Handler()
}

func (s *metricService) IncServerCount() {
s.serverCount.WithLabelValues().Inc()
}

func (s *metricService) DecServerCount() {
s.serverCount.WithLabelValues().Dec()
}

func (s *metricService) ObserveRequestDuration(handler, code, method string, duration float64) {
s.requestDuration.WithLabelValues(handler, code, method).Observe(duration)
}

func (s *metricService) IncRequestTotal(handler, code, method string) {
s.requestTotal.WithLabelValues(handler, code, method).Inc()
}
10 changes: 7 additions & 3 deletions internal/services/server_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ type ServerService interface {
}

type serverService struct {
storage storage.Storage
storage storage.Storage
metricService MetricService
}

func NewServerService(s storage.Storage) ServerService {
func NewServerService(s storage.Storage, m MetricService) ServerService {
return &serverService{
storage: s,
storage: s,
metricService: m,
}
}

Expand All @@ -33,6 +35,7 @@ func (s *serverService) UpdateServer(ID string, server models.ServerModel) error
}

func (s *serverService) DeleteServer(ID string) error {
s.metricService.DecServerCount()
return s.storage.Delete(ID)
}

Expand All @@ -45,5 +48,6 @@ func (s *serverService) SearchServers(search []models.SearchRequest) ([]models.S
}

func (s *serverService) CreateServer(server models.ServerModel) error {
s.metricService.IncServerCount()
return s.storage.Add(server)
}
15 changes: 12 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,28 @@ package main

import (
"game-server-selector/internal/domain"
"game-server-selector/internal/server/http"
serverhttp "game-server-selector/internal/server/http"
"game-server-selector/internal/services"
"game-server-selector/internal/storage"

"net/http"
)

func main() {
configService := services.NewConfigService()
//TODO: after added new storage support we need to check config and init storage
inMemoryStorage := storage.NewInMemoryStorage()
serverService := services.NewServerService(inMemoryStorage)
metricService := services.NewMetricService()
metricService.Register()
serverService := services.NewServerService(inMemoryStorage, metricService)
serverDomain := domain.NewServerDomain(serverService, configService)

fiber := http.NewFiberServer(serverDomain, configService)
if configService.IsPrometheusEnabled() {
handler := metricService.Handler()
http.Handle("/metrics", handler)
go http.ListenAndServe(configService.GetPrometheusPort(), nil)
}
fiber := serverhttp.NewFiberServer(serverDomain, configService, metricService)
err := fiber.Start()
if err != nil {
panic(err)
Expand Down

0 comments on commit d700be3

Please sign in to comment.