Skip to content

Commit

Permalink
feat: prometheus metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
lmendes86 committed Sep 5, 2024
1 parent 2dc347d commit fad92ad
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 139 deletions.
15 changes: 12 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
module github.com/resgateio/resgate

go 1.22
go 1.23

toolchain go1.23.0

require (
github.com/bsm/openmetrics v0.3.1
github.com/gorilla/websocket v1.5.3
github.com/jirenius/timerqueue v1.0.0
github.com/nats-io/nats.go v1.37.0
github.com/posener/wstest v1.2.0
github.com/prometheus/client_golang v1.20.3
github.com/rs/xid v1.6.0
)

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.59.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/sys v0.25.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
)
35 changes: 28 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
github.com/bsm/openmetrics v0.3.1 h1:nhR6QgaKaDmnbnvVP9R0JyPExt8Qa+n1cJk/ouGC4FY=
github.com/bsm/openmetrics v0.3.1/go.mod h1:tabLMhjVjhdhFuwm9YenEVx0s54uvu56faEwYgD6L2g=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
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.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.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=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/jirenius/timerqueue v1.0.0 h1:TgcUQlrxKBBHYmStXPzLdMPJFfmqkWZZ1s7BA5G1d9E=
github.com/jirenius/timerqueue v1.0.0/go.mod h1:pUEjy16BUruJMjLIsjWvWQh9Bu9CSXCIfGADZf37WIk=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE=
github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
Expand All @@ -19,15 +28,27 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/wstest v1.2.0 h1:PAY0cRybxOjh0yqSDCrlAGUwtx+GNKpuUfid/08pv48=
github.com/posener/wstest v1.2.0/go.mod h1:GkplCx9zskpudjrMp23LyZHrSonab0aZzh2x0ACGRbU=
github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4=
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.59.0 h1:o2eVCLbhf3sgisnD5e0/twUt25r8gNmMHNzTOAuY9bs=
github.com/prometheus/common v0.59.0/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
6 changes: 3 additions & 3 deletions server/apiHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (s *Service) apiHandler(w http.ResponseWriter, r *http.Request) {
case "GET":
// Metrics
if s.metrics != nil {
s.metrics.HTTPRequestsGet.Add(1)
s.metrics.HTTPRequests.WithLabelValues("GET").Add(1)
}

rid = PathToRID(path, r.URL.RawQuery, apiPath)
Expand All @@ -114,7 +114,7 @@ func (s *Service) apiHandler(w http.ResponseWriter, r *http.Request) {
case "POST":
// Metrics
if s.metrics != nil {
s.metrics.HTTPRequestsPost.Add(1)
s.metrics.HTTPRequests.WithLabelValues("POST").Add(1)
}

rid, action = PathToRIDAction(path, r.URL.RawQuery, apiPath)
Expand Down Expand Up @@ -142,7 +142,7 @@ func (s *Service) apiHandler(w http.ResponseWriter, r *http.Request) {

// Metrics
if s.metrics != nil {
s.metrics.HTTPRequests.With(r.Method).Add(1)
s.metrics.HTTPRequests.WithLabelValues(r.Method).Add(1)
}

rid = PathToRID(path, r.URL.RawQuery, apiPath)
Expand Down
147 changes: 56 additions & 91 deletions server/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,121 +2,86 @@ package metrics

import (
"regexp"
"runtime"

"github.com/bsm/openmetrics"
"github.com/prometheus/client_golang/prometheus"
)

var (
uUIDRegex = regexp.MustCompile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")
iDRegex = regexp.MustCompile("[0-9]+")
uUIDRegex = regexp.MustCompile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")
iDRegex = regexp.MustCompile("[0-9]+")
stringIDRegex = regexp.MustCompile(`^(dashboard\.signed\.).*$`)
)

type MetricSet struct {
m runtime.MemStats
// Memstats
MemSysBytes openmetrics.Gauge
// WebSocket connectionws
WSConnections openmetrics.Gauge
WSConnectionCount openmetrics.Counter
WSConnections prometheus.Gauge
// WebSocket requests
WSRequestsGet openmetrics.Counter
WSRequestsSubscribe openmetrics.Counter
WSRequestsUnsubscribe openmetrics.Counter
WSRequestsCall openmetrics.Counter
WSRequestsAuth openmetrics.Counter
WSRequests *prometheus.CounterVec
// Cache
CacheResources openmetrics.Gauge
CacheSubscriptions openmetrics.Gauge
CacheResources prometheus.Gauge
CacheSubscriptions *prometheus.GaugeVec
// HTTP requests
HTTPRequests openmetrics.CounterFamily
HTTPRequestsGet openmetrics.Counter
HTTPRequestsPost openmetrics.Counter
// Subscriptions
SubcriptionsCount openmetrics.GaugeFamily
HTTPRequests *prometheus.CounterVec
}

// Scrape updates the metric set with info on current mem usage.
func (m *MetricSet) Scrape() {
runtime.ReadMemStats(&m.m)
m.MemSysBytes.Set(float64(m.m.Sys))
}

func (m *MetricSet) Register(reg *openmetrics.Registry, version string, protocolVersion string) {
// Go info
reg.Info(openmetrics.Desc{
Name: "go",
Help: "Information about the Go environment.",
Labels: []string{"version"},
}).With(runtime.Version())

func (m *MetricSet) Register(version string, protocolVersion string) {
// Resgate info
reg.Info(openmetrics.Desc{
Name: "resgate",
Help: "Information about resgate.",
Labels: []string{"version", "protocol"},
}).With(version, protocolVersion)

// Memory stats
m.MemSysBytes = reg.Gauge(openmetrics.Desc{
Name: "go_memstats_sys_bytes",
Help: "Number of bytes obtained from system.",
}).With()
m.MemSysBytes.Set(0)
prometheus.MustRegister(prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: "resgate",
Name: "info",
Help: "Information about resgate.",
ConstLabels: prometheus.Labels{
"version": version,
"protocol": protocolVersion,
},
}))

// WebSocket connections
m.WSConnections = reg.Gauge(openmetrics.Desc{
Name: "resgate_ws_current_connections",
Help: "Current established WebSocket connections.",
}).With()
m.WSConnections.Set(0)
m.WSConnectionCount = reg.Counter(openmetrics.Desc{
Name: "resgate_ws_connections",
Help: "Total established WebSocket connections.",
}).With()

// WebSocket requests
wsRequests := reg.Counter(openmetrics.Desc{
Name: "resgate_ws_requests",
Help: "Total WebSocket client requests.",
Labels: []string{"method"},
m.WSConnections = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: "resgate",
Subsystem: "ws",
Name: "current_connections",
Help: "Current established WebSocket connections.",
})
m.WSRequestsGet = wsRequests.With("get")
m.WSRequestsSubscribe = wsRequests.With("subscribe")
m.WSRequestsUnsubscribe = wsRequests.With("unsubscribe")
m.WSRequestsCall = wsRequests.With("call")
m.WSRequestsAuth = wsRequests.With("auth")
prometheus.MustRegister(m.WSConnections)

// HTTP requests
m.HTTPRequests = reg.Counter(openmetrics.Desc{
Name: "resgate_http_requests",
Help: "Total HTTP client requests.",
Labels: []string{"method"},
})
m.HTTPRequestsGet = m.HTTPRequests.With("GET")
m.HTTPRequestsPost = m.HTTPRequests.With("POST")
// WebSocket requests
m.WSRequests = prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "resgate",
Subsystem: "ws",
Name: "requests",
Help: "Total WebSocket client requests.",
}, []string{"method"})
prometheus.MustRegister(m.WSRequests)

// Cache
m.CacheResources = reg.Gauge(openmetrics.Desc{
Name: "resgate_cache_resources",
Help: "Current number of resources stored in the cache.",
}).With()
m.CacheResources.Set(0)
m.CacheSubscriptions = reg.Gauge(openmetrics.Desc{
Name: "resgate_cache_subscriptions",
Help: "Current number of subscriptions on cached resources.",
}).With()
m.CacheSubscriptions.Set(0)

// Subscriptions
m.SubcriptionsCount = reg.Gauge(openmetrics.Desc{
Name: "resgate_cache_subscriptions",
Help: "Number of subscriptions per sanitized name.",
Labels: []string{"name"},
m.CacheResources = prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: "resgate",
Subsystem: "cache",
Name: "resources",
Help: "Current number of resources stored in the cache.",
})
prometheus.MustRegister(m.CacheResources)
m.CacheSubscriptions = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: "resgate",
Subsystem: "cache",
Name: "subscriptions",
Help: "Current number of subscriptions on cached resources.",
}, []string{"name"})
prometheus.MustRegister(m.CacheSubscriptions)

// HTTP requests
m.HTTPRequests = prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "resgate",
Subsystem: "http",
Name: "requests",
Help: "Total HTTP client requests.",
}, []string{"method"})
prometheus.MustRegister(m.HTTPRequests)
}

func SanitizedString(s string) string {
s = stringIDRegex.ReplaceAllString(s, "$1{stringid}")
s = uUIDRegex.ReplaceAllString(s, "{uuid}")
s = iDRegex.ReplaceAllString(s, "{id}")
return s
Expand Down
25 changes: 5 additions & 20 deletions server/metricsServer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import (
"net/http"
"time"

"github.com/bsm/openmetrics"
"github.com/bsm/openmetrics/omhttp"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/resgateio/resgate/server/metrics"
)

Expand All @@ -31,27 +30,14 @@ func (s *Service) startMetricsServer() {
return
}

reg := openmetrics.NewConsistentRegistry(func() time.Time { return time.Now() })
ms := s.metrics
ms.Register(reg, Version, ProtocolVersion)

h := omhttp.NewHandler(reg)
s.metricsh = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ms.Scrape()
h.ServeHTTP(w, r)
})

// For testing
if s.cfg.NoHTTP {
return
}
s.metrics.Register(Version, ProtocolVersion)

mux := http.NewServeMux()
mux.Handle(MetricsPattern, s.metricsh)
mux.Handle(MetricsPattern, promhttp.Handler())

hln, err := net.Listen("tcp", s.cfg.metricsNetAddr)
if err != nil {
s.Logf("Metrics server can't listen on %s: %s", s.cfg.metricsNetAddr, err)
s.Logf("Metrics server can't listin on %s", s.cfg.metricsNetAddr)
return
}

Expand All @@ -60,7 +46,7 @@ func (s *Service) startMetricsServer() {
}
s.m = metricsServer

s.Logf("Metrics endpoint listening on %s://%s%s", s.cfg.scheme, s.cfg.metricsNetAddr, MetricsPattern)
s.Logf("Metrics endpoint listening on %s://%s", s.cfg.scheme, s.cfg.metricsNetAddr)

go func() {
var err error
Expand All @@ -74,7 +60,6 @@ func (s *Service) startMetricsServer() {
s.Stop(err)
}
}()

}

// stopMetricsServer stops the Metrics server
Expand Down
8 changes: 3 additions & 5 deletions server/rescache/eventSubscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ func (e *EventSubscription) addSubscriber(sub Subscriber, t *Throttle, requestHe

// Metrics
if e.cache.metrics != nil {
e.cache.metrics.CacheSubscriptions.Add(-1)
e.cache.metrics.SubcriptionsCount.With(metrics.SanitizedString(e.ResourceName)).Set(float64(e.count))
e.cache.metrics.CacheSubscriptions.WithLabelValues(metrics.SanitizedString(e.ResourceName)).Set(float64(e.count))
}

sub.Loaded(nil, nil, rs.err)
Expand Down Expand Up @@ -221,7 +220,7 @@ func (e *EventSubscription) addCount() {
}
e.count++
if e.cache.metrics != nil {
e.cache.metrics.SubcriptionsCount.With(metrics.SanitizedString(e.ResourceName)).Set(float64(e.count))
e.cache.metrics.CacheSubscriptions.WithLabelValues(metrics.SanitizedString(e.ResourceName)).Set(float64(e.count))
}
}

Expand All @@ -235,8 +234,7 @@ func (e *EventSubscription) removeCount(n int64) {

// Metrics
if e.cache.metrics != nil {
e.cache.metrics.CacheSubscriptions.Add(float64(-n))
e.cache.metrics.SubcriptionsCount.With(metrics.SanitizedString(e.ResourceName)).Set(float64(e.count))
e.cache.metrics.CacheSubscriptions.WithLabelValues(metrics.SanitizedString(e.ResourceName)).Set(float64(e.count))
}
}

Expand Down
Loading

0 comments on commit fad92ad

Please sign in to comment.