diff --git a/api/api_types.go b/api/api_types.go index 0262268dc..00c898dac 100644 --- a/api/api_types.go +++ b/api/api_types.go @@ -198,7 +198,7 @@ type GenericTransactionWithInfo struct { type ChainInfo struct { ID string `json:"chainId" example:"azeno"` - BlockTime [5]int32 `json:"blockTime" example:"12000,11580,11000,11100,11100"` + BlockTime [5]uint64 `json:"blockTime" example:"12000,11580,11000,11100,11100"` ElectionCount uint64 `json:"electionCount" example:"120"` OrganizationCount uint64 `json:"organizationCount" example:"20"` GenesisTime time.Time `json:"genesisTime" format:"date-time" example:"2022-11-17T18:00:57.379551614Z"` diff --git a/api/chain.go b/api/chain.go index 14626bccb..6135cb83e 100644 --- a/api/chain.go +++ b/api/chain.go @@ -400,7 +400,7 @@ func (a *API) chainEstimateHeightHandler(_ *apirest.APIdata, ctx *httprouter.HTT // @Success 200 {object} object{date=string} // @Router /chain/blockToDate/{height} [get] func (a *API) chainEstimateDateHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error { - height, err := strconv.ParseInt(ctx.URLParam("height"), 10, 64) + height, err := strconv.ParseUint(ctx.URLParam("height"), 10, 64) if err != nil { return err } @@ -737,11 +737,11 @@ func (a *API) chainValidatorsHandler(_ *apirest.APIdata, ctx *httprouter.HTTPCon // @Success 200 {object} api.Block // @Router /chain/blocks/{height} [get] func (a *API) chainBlockHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error { - height, err := strconv.ParseInt(ctx.URLParam("height"), 10, 64) + height, err := strconv.ParseUint(ctx.URLParam("height"), 10, 64) if err != nil { return err } - tmblock := a.vocapp.GetBlockByHeight(height) + tmblock := a.vocapp.GetBlockByHeight(int64(height)) if tmblock == nil { return ErrBlockNotFound } diff --git a/api/helpers.go b/api/helpers.go index cc4d58ac1..d651d68f9 100644 --- a/api/helpers.go +++ b/api/helpers.go @@ -25,8 +25,8 @@ func (a *API) electionSummary(pi *indexertypes.Process) ElectionSummary { ElectionID: pi.ID, OrganizationID: pi.EntityID, Status: models.ProcessStatus_name[pi.Status], - StartDate: a.vocinfo.HeightTime(int64(pi.StartBlock)), - EndDate: a.vocinfo.HeightTime(int64(pi.EndBlock)), + StartDate: a.vocinfo.HeightTime(uint64(pi.StartBlock)), + EndDate: a.vocinfo.HeightTime(uint64(pi.EndBlock)), FinalResults: pi.FinalResults, VoteCount: pi.VoteCount, ManuallyEnded: pi.EndBlock < pi.StartBlock+pi.BlockCount, diff --git a/cmd/node/main.go b/cmd/node/main.go index b139aa7a7..4338d53ec 100644 --- a/cmd/node/main.go +++ b/cmd/node/main.go @@ -30,7 +30,6 @@ import ( "go.vocdoni.io/dvote/httprouter" "go.vocdoni.io/dvote/internal" "go.vocdoni.io/dvote/log" - "go.vocdoni.io/dvote/metrics" "go.vocdoni.io/dvote/service" "go.vocdoni.io/dvote/types" "go.vocdoni.io/dvote/vochain" @@ -507,8 +506,9 @@ func main() { } // Enable metrics via proxy if conf.Metrics.Enabled { - srv.MetricsAgent = metrics.NewAgent("/metrics", - time.Duration(conf.Metrics.RefreshInterval)*time.Second, srv.Router) + // This flag will make CometBFT register their metrics in prometheus + srv.Config.TendermintMetrics = true + srv.Router.ExposePrometheusEndpoint("/metrics") } } diff --git a/cmd/voconed/voconed.go b/cmd/voconed/voconed.go index 5ceac7d90..f1afef020 100644 --- a/cmd/voconed/voconed.go +++ b/cmd/voconed/voconed.go @@ -19,7 +19,6 @@ import ( "go.vocdoni.io/dvote/crypto/zk/circuit" "go.vocdoni.io/dvote/internal" "go.vocdoni.io/dvote/log" - "go.vocdoni.io/dvote/metrics" "go.vocdoni.io/dvote/vochain/state" "go.vocdoni.io/dvote/vocone" "go.vocdoni.io/proto/build/go/models" @@ -232,8 +231,7 @@ func main() { log.Fatal(err) } - vc.MetricsAgent = metrics.NewAgent("/metrics", - time.Duration(10)*time.Second, vc.Router) + vc.Router.ExposePrometheusEndpoint("/metrics") // enable faucet if requested, this will create a new account and attach the faucet API to the vocone API if config.enableFaucetWithAmount > 0 { diff --git a/data/ipfs/ipfs.go b/data/ipfs/ipfs.go index ec4704318..8646854c5 100644 --- a/data/ipfs/ipfs.go +++ b/data/ipfs/ipfs.go @@ -133,7 +133,6 @@ func (i *Handler) Init(d *types.DataStore) error { } go i.updateStats(time.Minute) - i.registerMetrics() return nil } @@ -221,7 +220,7 @@ func (i *Handler) Unpin(ctx context.Context, path string) error { // Stats returns stats about the IPFS node. func (i *Handler) Stats() map[string]any { - return map[string]any{"peers": stats.Peers.Load(), "addresses": stats.KnownAddrs.Load(), "pins": stats.Pins.Load()} + return map[string]any{"peers": stats.Peers.Get(), "addresses": stats.KnownAddrs.Get(), "pins": stats.Pins.Get()} } func (i *Handler) countPins(ctx context.Context) (int, error) { diff --git a/data/ipfs/metrics.go b/data/ipfs/metrics.go index 168ca6bad..fde08d568 100644 --- a/data/ipfs/metrics.go +++ b/data/ipfs/metrics.go @@ -5,40 +5,17 @@ import ( "sync" "time" - "github.com/prometheus/client_golang/prometheus" - "go.uber.org/atomic" - - "go.vocdoni.io/dvote/metrics" + "github.com/VictoriaMetrics/metrics" ) -var stats struct { - Peers atomic.Float64 - KnownAddrs atomic.Float64 - Pins atomic.Float64 -} - -// registerMetrics registers prometheus metrics -func (i *Handler) registerMetrics() { - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "file", - Name: "peers", - Help: "The number of connected peers", - }, - stats.Peers.Load)) - - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "file", - Name: "addresses", - Help: "The number of registered addresses", - }, - stats.KnownAddrs.Load)) - - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "file", - Name: "pins", - Help: "The number of pinned files", - }, - stats.Pins.Load)) +var stats = struct { + Peers *metrics.Counter + KnownAddrs *metrics.Counter + Pins *metrics.Counter +}{ + Peers: metrics.NewCounter("file_peers"), + KnownAddrs: metrics.NewCounter("file_addresses"), + Pins: metrics.NewCounter("file_pins"), } // updateStats constantly updates the ipfs stats (Peers, KnownAddrs, Pins) @@ -55,7 +32,7 @@ func (i *Handler) updateStats(interval time.Duration) { go func() { list, err := i.CoreAPI.Swarm().Peers(ctx) if err == nil { - stats.Peers.Store(float64(len(list))) + stats.Peers.Set(uint64(len(list))) } wg.Done() }() @@ -64,7 +41,7 @@ func (i *Handler) updateStats(interval time.Duration) { go func() { list, err := i.CoreAPI.Swarm().KnownAddrs(ctx) if err == nil { - stats.KnownAddrs.Store(float64(len(list))) + stats.KnownAddrs.Set(uint64(len(list))) } wg.Done() }() @@ -73,7 +50,7 @@ func (i *Handler) updateStats(interval time.Duration) { go func() { count, err := i.countPins(ctx) if err == nil { - stats.Pins.Store(float64(count)) + stats.Pins.Set(uint64(count)) } wg.Done() }() diff --git a/go.mod b/go.mod index 3949121f6..17ca08f5e 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ go 1.21 require ( git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9 github.com/766b/chi-prometheus v0.0.0-20211217152057-87afa9aa2ca8 + github.com/VictoriaMetrics/metrics v1.24.0 github.com/arnaucube/go-blindsecp256k1 v0.0.0-20211204171003-644e7408753f github.com/cockroachdb/pebble v0.0.0-20230620232302-06034ff014e0 github.com/cometbft/cometbft v0.38.0 @@ -58,7 +59,6 @@ require ( github.com/vocdoni/go-snark v0.0.0-20210709152824-f6e4c27d7319 github.com/vocdoni/storage-proofs-eth-go v0.1.6 go.mongodb.org/mongo-driver v1.12.1 - go.uber.org/atomic v1.11.0 go.vocdoni.io/proto v1.15.4-0.20231023165811-02adcc48142a golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20230905200255-921286631fa9 @@ -270,6 +270,8 @@ require ( github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.4.0 // indirect github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect + github.com/valyala/fastrand v1.1.0 // indirect + github.com/valyala/histogram v1.2.0 // indirect github.com/wasmerio/wasmer-go v1.0.4 // indirect github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect @@ -298,6 +300,7 @@ require ( go.opentelemetry.io/otel/sdk v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect + go.uber.org/atomic v1.11.0 // indirect go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.20.0 // indirect go.uber.org/multierr v1.11.0 // indirect diff --git a/go.sum b/go.sum index 52416c263..bbf0ee80b 100644 --- a/go.sum +++ b/go.sum @@ -101,6 +101,8 @@ github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= +github.com/VictoriaMetrics/metrics v1.24.0 h1:ILavebReOjYctAGY5QU2F9X0MYvkcrG3aEn2RKa1Zkw= +github.com/VictoriaMetrics/metrics v1.24.0/go.mod h1:eFT25kvsTidQFHb6U0oa0rTrDRdz4xTYjpL8+UPohys= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= @@ -1504,8 +1506,12 @@ github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3 github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8= +github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OLoQ= +github.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= diff --git a/httprouter/httprouter.go b/httprouter/httprouter.go index 62514a1f6..c6e1eabf9 100644 --- a/httprouter/httprouter.go +++ b/httprouter/httprouter.go @@ -13,10 +13,12 @@ import ( "time" chiprometheus "github.com/766b/chi-prometheus" + "github.com/VictoriaMetrics/metrics" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" reuse "github.com/libp2p/go-reuseport" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/rs/zerolog" "go.vocdoni.io/dvote/log" "golang.org/x/crypto/acme" @@ -170,6 +172,21 @@ func (r *HTTProuter) EnablePrometheusMetrics(prometheusID string) { r.Mux.Use(chiprometheus.NewMiddleware(prometheusID)) } +// ExposePrometheusEndpoint registers a HTTPHandler at the passed path +// that will expose the metrics collected by VictoriaMetrics and Prometheus +func (r *HTTProuter) ExposePrometheusEndpoint(path string) { + r.AddRawHTTPHandler(path, "GET", func(w http.ResponseWriter, req *http.Request) { + // upstream packages (cometbft, libp2p) call prometheus.Register(), so expose those metrics first + promhttp.Handler().ServeHTTP(w, req) + + // then append the metrics registered in VictoriaMetrics (our metrics, basically) + // don't exposeProcessMetrics here since the go_* and process_* are already part of the output of + // the previous promhttp.Handler().ServeHTTP() + metrics.WritePrometheus(w, false) + }) + log.Infof("prometheus metrics ready at: %s", path) +} + // Address return the current network address used by the HTTP router func (r *HTTProuter) Address() net.Addr { return r.address diff --git a/metrics/metrics.go b/metrics/metrics.go deleted file mode 100644 index 6e08e7538..000000000 --- a/metrics/metrics.go +++ /dev/null @@ -1,32 +0,0 @@ -package metrics - -import ( - "time" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "go.vocdoni.io/dvote/httprouter" - "go.vocdoni.io/dvote/log" -) - -// Agent struct with options -type Agent struct { - Path string - RefreshInterval time.Duration -} - -// NewAgent creates and initializes the metrics agent with a HTTP server -func NewAgent(path string, interval time.Duration, router *httprouter.HTTProuter) *Agent { - ma := Agent{Path: path, RefreshInterval: interval} - router.AddRawHTTPHandler(path, "GET", promhttp.Handler().ServeHTTP) - log.Infof("prometheus metrics ready at: %s", path) - return &ma -} - -// Register the provided prometheus collector, ignoring any error returned (simply logs a Warn) -func Register(c prometheus.Collector) { - err := prometheus.Register(c) - if err != nil { - log.Warnf("cannot register metrics: (%s) (%+v)", err, c) - } -} diff --git a/service/service.go b/service/service.go index 8fbcb108e..90213c341 100644 --- a/service/service.go +++ b/service/service.go @@ -7,7 +7,6 @@ import ( "go.vocdoni.io/dvote/data" "go.vocdoni.io/dvote/data/downloader" "go.vocdoni.io/dvote/httprouter" - "go.vocdoni.io/dvote/metrics" "go.vocdoni.io/dvote/vochain" "go.vocdoni.io/dvote/vochain/indexer" "go.vocdoni.io/dvote/vochain/keykeeper" @@ -20,7 +19,6 @@ type VocdoniService struct { Config *config.VochainCfg App *vochain.BaseApplication Router *httprouter.HTTProuter - MetricsAgent *metrics.Agent OffChainData *offchaindatahandler.OffChainDataHandler DataDownloader *downloader.Downloader CensusDB *censusdb.CensusDB diff --git a/service/vochain.go b/service/vochain.go index fc5a66a26..a18fc607f 100644 --- a/service/vochain.go +++ b/service/vochain.go @@ -97,11 +97,6 @@ func (vs *VocdoniService) Vochain() error { } } - // Metrics agent (Prometheus) - if vs.MetricsAgent != nil { - vs.Config.TendermintMetrics = true - } - // Create the vochain node vs.App = vochain.NewVochain(vs.Config, genesisBytes) @@ -136,7 +131,7 @@ func (vs *VocdoniService) Start() error { if !vs.Config.NoWaitSync { log.Infof("waiting for vochain to synchronize") - var lastHeight int64 + var lastHeight uint64 i := 0 timeSyncCounter := time.Now() timeCounter := time.Now() @@ -171,10 +166,10 @@ func (vs *VocdoniService) Start() error { // VochainPrintInfo initializes the Vochain statistics recollection. func VochainPrintInfo(interval time.Duration, vi *vochaininfo.VochainInfo) { - var a *[5]int32 - var h int64 + var a *[5]uint64 + var h uint64 var p, v uint64 - var m, vc, vxm int + var m, vc, vxm uint64 var b strings.Builder for { b.Reset() diff --git a/subpub/discovery.go b/subpub/discovery.go index d6655fa7f..32370bbb7 100644 --- a/subpub/discovery.go +++ b/subpub/discovery.go @@ -4,24 +4,20 @@ import ( "context" "time" + "github.com/VictoriaMetrics/metrics" corediscovery "github.com/libp2p/go-libp2p/core/discovery" libpeer "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" discrouting "github.com/libp2p/go-libp2p/p2p/discovery/routing" discutil "github.com/libp2p/go-libp2p/p2p/discovery/util" multiaddr "github.com/multiformats/go-multiaddr" - "github.com/prometheus/client_golang/prometheus" "go.vocdoni.io/dvote/log" - "go.vocdoni.io/dvote/metrics" ) // Metrics exported via prometheus var ( - dhtLatency = prometheus.NewHistogram(prometheus.HistogramOpts{ - Namespace: "file", - Name: "peers_dht_latency", - Help: "The time it takes FindPeers to discover peers", - }) + // The time it takes FindPeers to discover peers + dhtLatency = metrics.NewHistogram("file_peers_dht_latency") ) // setupDiscovery creates a DHT discovery service and attaches it to the libp2p Host. @@ -39,8 +35,6 @@ func (s *SubPub) setupDiscovery(ctx context.Context) { s.routing = discrouting.NewRoutingDiscovery(s.node.DHT) discutil.Advertise(ctx, s.routing, s.Topic) - metrics.Register(dhtLatency) - // Discover new peers periodically go func() { // this spawns a single background task per instance for { @@ -58,7 +52,8 @@ func (s *SubPub) setupDiscovery(ctx context.Context) { } func (s *SubPub) discover(ctx context.Context) { - dhtLatencyTimer := prometheus.NewTimer(dhtLatency) + startTime := time.Now() + // Now, look for others who have announced. // This is like your friend telling you the location to meet you. log.Debugf("looking for peers in topic %s", s.Topic) @@ -83,7 +78,7 @@ func (s *SubPub) discover(ctx context.Context) { } // new peer; let's connect to it // first update the latency metrics - dhtLatencyTimer.ObserveDuration() + dhtLatency.UpdateDuration(startTime) connectCtx, cancel := context.WithTimeout(ctx, time.Second*10) if err := s.node.PeerHost.Connect(connectCtx, peer); err != nil { cancel() diff --git a/vochain/vochaininfo/metrics.go b/vochain/vochaininfo/metrics.go index 2f7f32d76..6c6262f33 100644 --- a/vochain/vochaininfo/metrics.go +++ b/vochain/vochaininfo/metrics.go @@ -1,72 +1,13 @@ package vochaininfo -import ( - "github.com/prometheus/client_golang/prometheus" - "go.vocdoni.io/dvote/metrics" +import "github.com/VictoriaMetrics/metrics" + +var ( + height = metrics.NewCounter("vochain_height") // Height of the vochain (last block) + voteCount = metrics.NewCounter("vochain_vote_tree") // Total vote count + processTreeSize = metrics.NewCounter("vochain_process_tree") // Size of the process tree + accountTreeSize = metrics.NewCounter("vochain_account_tree") // Size of the account tree + sikTreeSize = metrics.NewCounter("vochain_sik_tree") // Size of the SIK tree + mempoolSize = metrics.NewCounter("vochain_mempool") // Number of Txs in the mempool + voteCacheSize = metrics.NewCounter("vochain_vote_cache") // Size of the current vote cache ) - -// registerMetrics registers each of the vochain prometheus metrics -func (vi *VochainInfo) registerMetrics() { - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "vochain", - Name: "height", - Help: "Height of the vochain (last block)", - }, - func() float64 { return float64(vi.Height()) })) - - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "vochain", - Name: "mempool", - Help: "Number of Txs in the mempool", - }, - func() float64 { return float64(vi.MempoolSize()) })) - - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "vochain", - Name: "process_tree", - Help: "Size of the process tree", - }, - func() float64 { p, _, _ := vi.TreeSizes(); return float64(p) })) - - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "vochain", - Name: "vote_tree", - Help: "Size of the vote tree", - }, - func() float64 { _, v, _ := vi.TreeSizes(); return float64(v) })) - - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "vochain", - Name: "vote_tree_increase_last_minute", - Help: "Number of votes included in the vote tree the last 60 seconds", - }, - func() float64 { _, _, vxm := vi.TreeSizes(); return float64(vxm) })) - - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "vochain", - Name: "vote_cache", - Help: "Size of the current vote cache", - }, - func() float64 { return float64(vi.VoteCacheSize()) })) - - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "vochain", - Name: "account_tree", - Help: "Size of the account tree", - }, - func() float64 { return float64(vi.AccountTreeSize()) })) - - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "vochain", - Name: "sik_tree", - Help: "Size of the SIK tree", - }, - func() float64 { return float64(vi.SIKTreeSize()) })) - - metrics.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{ - Namespace: "vochain", - Name: "tokens_burned", - Help: "Balance of the burn address", - }, - func() float64 { return float64(vi.TokensBurned()) })) -} diff --git a/vochain/vochaininfo/vochaininfo.go b/vochain/vochaininfo/vochaininfo.go index f30f85356..a266a736c 100644 --- a/vochain/vochaininfo/vochaininfo.go +++ b/vochain/vochaininfo/vochaininfo.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/VictoriaMetrics/metrics" coretypes "github.com/cometbft/cometbft/rpc/core/types" "go.vocdoni.io/dvote/log" "go.vocdoni.io/dvote/vochain" @@ -16,26 +17,16 @@ import ( // VochainInfo stores some metrics and information regarding the Vochain Blockchain // Avg1/10/60/360 are the block time average for 1 minute, 10 minutes, 1 hour and 6 hours type VochainInfo struct { - sync bool - height int64 - // NOTE(Edu): After the integration of the arbo-based StateDB, there's - // no single voteTree, but we can still count total number of votes. A - // more appropriate name for this variable would be voteCount - voteTreeSize uint64 - processTreeSize uint64 - accountTreeSize uint64 - sikTreeSize uint64 - mempoolSize int - voteCacheSize int - votesPerMinute int - avg1 int32 - avg10 int32 - avg60 int32 - avg360 int32 - avg1440 int32 - vnode *vochain.BaseApplication - close chan bool - lock sync.RWMutex + sync bool + votesPerMinute uint64 + avg1 uint64 + avg10 uint64 + avg60 uint64 + avg360 uint64 + avg1440 uint64 + vnode *vochain.BaseApplication + close chan bool + lock sync.RWMutex } // NewVochainInfo creates a new VochainInfo type @@ -46,19 +37,48 @@ func NewVochainInfo(node *vochain.BaseApplication) *VochainInfo { } } +func (vi *VochainInfo) updateCounters() { + height.Set(uint64(vi.vnode.Height())) + + pc, err := vi.vnode.State.CountProcesses(true) + if err != nil { + log.Errorf("cannot count processes: %s", err) + } + processTreeSize.Set(pc) + + vc, err := vi.vnode.State.CountTotalVotes() + if err != nil { + log.Errorf("cannot access vote count: %s", err) + } + voteCount.Set(vc) + + ac, err := vi.vnode.State.CountAccounts(true) + if err != nil { + log.Errorf("cannot count accounts: %s", err) + } + accountTreeSize.Set(ac) + + sc, err := vi.vnode.State.CountSIKs(true) + if err != nil { + log.Errorf("cannot count SIKs: %s", err) + } + sikTreeSize.Set(sc) + + voteCacheSize.Set(uint64(vi.vnode.State.CacheSize())) + mempoolSize.Set(uint64(vi.vnode.MempoolSize())) +} + // Height returns the current number of blocks of the blockchain -func (vi *VochainInfo) Height() int64 { - vi.lock.RLock() - defer vi.lock.RUnlock() - return vi.height +func (vi *VochainInfo) Height() uint64 { + return height.Get() } // BlockTimes returns the average block time in milliseconds for 1, 10, 60, 360 and 1440 minutes. // Value 0 means there is not yet an average -func (vi *VochainInfo) BlockTimes() *[5]int32 { +func (vi *VochainInfo) BlockTimes() *[5]uint64 { vi.lock.RLock() defer vi.lock.RUnlock() - return &[5]int32{vi.avg1, vi.avg10, vi.avg60, vi.avg360, vi.avg1440} + return &[5]uint64{vi.avg1, vi.avg10, vi.avg60, vi.avg360, vi.avg1440} } // EstimateBlockHeight provides an estimation time for a future blockchain height number. @@ -113,13 +133,13 @@ func (vi *VochainInfo) EstimateBlockHeight(target time.Time) (uint64, error) { // HeightTime estimates the UTC time for a future height or returns the // block timestamp if height is in the past. -func (vi *VochainInfo) HeightTime(height int64) time.Time { +func (vi *VochainInfo) HeightTime(height uint64) time.Time { times := vi.BlockTimes() currentHeight := vi.Height() - diffHeight := height - currentHeight + diffHeight := int64(height - currentHeight) if diffHeight < 0 { - blk := vi.vnode.GetBlockByHeight(height) + blk := vi.vnode.GetBlockByHeight(int64(height)) if blk == nil { log.Errorf("cannot get block height %d", height) return time.Time{} @@ -127,16 +147,16 @@ func (vi *VochainInfo) HeightTime(height int64) time.Time { return blk.Header.Time } - getMaxTimeFrom := func(i int) int64 { + getMaxTimeFrom := func(i int) uint64 { for ; i >= 0; i-- { if times[i] != 0 { - return int64(times[i]) + return times[i] } } return 10000 // fallback } - t := int64(0) + t := uint64(0) switch { // if less than around 15 minutes missing case diffHeight < 100: @@ -148,48 +168,40 @@ func (vi *VochainInfo) HeightTime(height int64) time.Time { case diffHeight >= 1000: t = getMaxTimeFrom(4) } - return time.Now().Add(time.Duration(diffHeight*t) * time.Millisecond) + return time.Now().Add(time.Duration(diffHeight*int64(t)) * time.Millisecond) } // TreeSizes returns the current size of the ProcessTree, VoteTree and the votes per minute // ProcessTree: total number of created voting processes in the blockchain // VoteTree: total number of votes registered in the blockchain // VotesPerMinute: number of votes included in the last 60 seconds -func (vi *VochainInfo) TreeSizes() (uint64, uint64, int) { +func (vi *VochainInfo) TreeSizes() (uint64, uint64, uint64) { vi.lock.RLock() defer vi.lock.RUnlock() - return vi.processTreeSize, vi.voteTreeSize, vi.votesPerMinute + return processTreeSize.Get(), voteCount.Get(), vi.votesPerMinute } // MempoolSize returns the current number of transactions waiting to be validated -func (vi *VochainInfo) MempoolSize() int { - vi.lock.RLock() - defer vi.lock.RUnlock() - return vi.mempoolSize +func (vi *VochainInfo) MempoolSize() uint64 { + return mempoolSize.Get() } // VoteCacheSize returns the current number of validated votes waiting to be // included in the blockchain -func (vi *VochainInfo) VoteCacheSize() int { - vi.lock.RLock() - defer vi.lock.RUnlock() - return vi.voteCacheSize +func (vi *VochainInfo) VoteCacheSize() uint64 { + return voteCacheSize.Get() } // AccountTreeSize returns the current number of validated votes waiting to be // included in the blockchain func (vi *VochainInfo) AccountTreeSize() uint64 { - vi.lock.RLock() - defer vi.lock.RUnlock() - return vi.accountTreeSize + return accountTreeSize.Get() } // SIKTreeSize returns the current number of validated votes waiting to be // included in the blockchain func (vi *VochainInfo) SIKTreeSize() uint64 { - vi.lock.RLock() - defer vi.lock.RUnlock() - return vi.sikTreeSize + return sikTreeSize.Get() } // TokensBurned returns the current balance of the burn address @@ -220,21 +232,26 @@ func (vi *VochainInfo) NPeers() int { // Start initializes the Vochain statistics recollection. // TODO: use time.Duration instead of int64 -func (vi *VochainInfo) Start(sleepSecs int64) { +func (vi *VochainInfo) Start(sleepSecs uint64) { log.Infof("starting vochain info service every %d seconds", sleepSecs) - vi.registerMetrics() + + metrics.NewGauge("vochain_tokens_burned", + func() float64 { return float64(vi.TokensBurned()) }) + var duration time.Duration - var pheight, height int64 - var h1, h10, h60, h360, h1440 int64 - var n1, n10, n60, n360, n1440, vm int64 - var a1, a10, a60, a360, a1440 int32 + var pheight, height uint64 + var h1, h10, h60, h360, h1440 uint64 + var n1, n10, n60, n360, n1440, vm uint64 + var a1, a10, a60, a360, a1440 uint64 var sync bool var oldVoteTreeSize uint64 duration = time.Second * time.Duration(sleepSecs) for { select { case <-time.After(duration): - height = int64(vi.vnode.Height()) + vi.updateCounters() + + height = uint64(vi.vnode.Height()) // less than 2s per block it's not real. Consider blockchain is synchcing if pheight > 0 { @@ -252,27 +269,27 @@ func (vi *VochainInfo) Start(sleepSecs int64) { h1440 += height - pheight if sleepSecs*n1 >= 60 && h1 > 0 { - a1 = int32((n1 * sleepSecs * 1000) / h1) + a1 = uint64((n1 * sleepSecs * 1000) / h1) n1 = 0 h1 = 0 } if sleepSecs*n10 >= 600 && h10 > 0 { - a10 = int32((n10 * sleepSecs * 1000) / h10) + a10 = uint64((n10 * sleepSecs * 1000) / h10) n10 = 0 h10 = 0 } if sleepSecs*n60 >= 3600 && h60 > 0 { - a60 = int32((n60 * sleepSecs * 1000) / h60) + a60 = uint64((n60 * sleepSecs * 1000) / h60) n60 = 0 h60 = 0 } if sleepSecs*n360 >= 21600 && h360 > 0 { - a360 = int32((n360 * sleepSecs * 1000) / h360) + a360 = uint64((n360 * sleepSecs * 1000) / h360) n360 = 0 h360 = 0 } if sleepSecs*n1440 >= 86400 && h1440 > 0 { - a1440 = int32((n1440 * sleepSecs * 1000) / h1440) + a1440 = uint64((n1440 * sleepSecs * 1000) / h1440) n1440 = 0 h1440 = 0 } @@ -282,37 +299,18 @@ func (vi *VochainInfo) Start(sleepSecs int64) { pheight = height vi.lock.Lock() - vi.height = height vi.sync = sync vi.avg1 = a1 vi.avg10 = a10 vi.avg60 = a60 vi.avg360 = a360 vi.avg1440 = a1440 - var err error - vi.processTreeSize, err = vi.vnode.State.CountProcesses(true) - if err != nil { - log.Errorf("cannot count processes: %s", err) - } - vi.voteTreeSize, err = vi.vnode.State.CountTotalVotes() - if err != nil { - log.Errorf("cannot access vote count: %s", err) - } - vi.accountTreeSize, err = vi.vnode.State.CountAccounts(true) - if err != nil { - log.Errorf("cannot count accounts: %s", err) - } - vi.sikTreeSize, err = vi.vnode.State.CountSIKs(true) - if err != nil { - log.Errorf("cannot count SIKs: %s", err) - } + if sleepSecs*vm >= 60 { - vi.votesPerMinute = int(vi.voteTreeSize) - int(oldVoteTreeSize) - oldVoteTreeSize = vi.voteTreeSize + vi.votesPerMinute = voteCount.Get() - oldVoteTreeSize + oldVoteTreeSize = voteCount.Get() vm = 0 } - vi.voteCacheSize = vi.vnode.State.CacheSize() - vi.mempoolSize = vi.vnode.MempoolSize() vi.lock.Unlock() case <-vi.close: diff --git a/vocone/vocone.go b/vocone/vocone.go index 4354b2955..07c331b5a 100644 --- a/vocone/vocone.go +++ b/vocone/vocone.go @@ -448,10 +448,10 @@ func (vc *Vocone) getTxWithHash(height uint32, txIndex int32) (*models.SignedTx, // VochainPrintInfo initializes the Vochain statistics recollection func vochainPrintInfo(interval time.Duration, vi *vochaininfo.VochainInfo) { - var a *[5]int32 - var h int64 + var a *[5]uint64 + var h uint64 var p, v uint64 - var m, vc, vxm int + var m, vc, vxm uint64 var b strings.Builder for { b.Reset()