Skip to content

Commit

Permalink
monitoring+tapd: register collectors to prometheus
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeTsagk committed Dec 13, 2023
1 parent 2096f52 commit 2ca8ec8
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 118 deletions.
19 changes: 18 additions & 1 deletion monitoring/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package monitoring

import "google.golang.org/grpc"
import (
"github.com/lightninglabs/taproot-assets/tapdb"
"github.com/lightninglabs/taproot-assets/tapgarden"
"github.com/lightninglabs/taproot-assets/universe"
"google.golang.org/grpc"
)

// PrometheusConfig is the set of configuration data that specifies if
// Prometheus metric exporting is activated, and if so the listening address of
Expand All @@ -17,6 +22,18 @@ type PrometheusConfig struct {
// generic RPC metrics to monitor the health of the service.
RPCServer *grpc.Server

// UniverseStats is used to collect any stats that are relevant to the
// universe.
UniverseStats universe.Telemetry

// AssetStore is used to collect any stats that are relevant to the
// asset store.
AssetStore *tapdb.AssetStore

// AssetMinter is used to collect any stats that are relevant to the
// asset minter.
AssetMinter tapgarden.Planter

// PerfHistograms indicates if the additional histogram information for
// latency, and handling time of gRPC calls should be enabled. This
// generates additional data, and consume more memory for the
Expand Down
29 changes: 0 additions & 29 deletions monitoring/interface.go

This file was deleted.

119 changes: 34 additions & 85 deletions monitoring/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"net/http"
"sync"
"time"

//nolint:lll
Expand All @@ -15,35 +14,29 @@ import (
)

var (
// metricGroups is a global variable of all registered metrics
// projected by the mutex below. All new MetricGroups should add
// themselves to this map within the init() method of their file.
metricGroups = make(map[string]metricGroupFactory)

// activeGroups is a global map of all active metric groups. This can
// be used by some of the "static' package level methods to look up the
// target metric group to export observations.
activeGroups = make(map[string]MetricGroup)

// metricsMtx is a global mutex that should be held when accessing the
// global maps.
metricsMtx sync.Mutex

// serverMetrics is a global variable that holds the Prometheus metrics
// for the gRPC server.
serverMetrics *grpc_prometheus.ServerMetrics
)

const (
// dbTimeout is the default database timeout.
dbTimeout = 20 * time.Second
)

// PrometheusExporter is a metric exporter that uses Prometheus directly. The
// internal server will interact with this struct in order to export relevant
// metrics.
type PrometheusExporter struct {
config *PrometheusConfig
config *PrometheusConfig
registry *prometheus.Registry
}

// Start registers all relevant metrics with the Prometheus library, then
// launches the HTTP server that Prometheus will hit to scrape our metrics.
func (p *PrometheusExporter) Start() error {
log.Infof("Starting Prometheus Exporter")

// If we're not active, then there's nothing more to do.
if !p.config.Active {
return nil
Expand All @@ -54,28 +47,42 @@ func (p *PrometheusExporter) Start() error {
return fmt.Errorf("server metrics not set")
}

reg := prometheus.NewRegistry()
reg.MustRegister(collectors.NewProcessCollector(
// Create a custom Prometheus registry.
p.registry = prometheus.NewRegistry()
p.registry.MustRegister(collectors.NewProcessCollector(
collectors.ProcessCollectorOpts{},
))
reg.MustRegister(collectors.NewGoCollector())
reg.MustRegister(serverMetrics)
p.registry.MustRegister(collectors.NewGoCollector())
p.registry.MustRegister(serverMetrics)

// Make ensure that all metrics exist when collecting and querying.
serverMetrics.InitializeMetrics(p.config.RPCServer)
uniStatsCollector, err := newUniverseStatsCollector(p.config, p.registry)
if err != nil {
return err
}
p.registry.MustRegister(uniStatsCollector)

// Next, we'll attempt to register all our metrics. If we fail to
// register ANY metric, then we'll fail all together.
if err := p.registerMetrics(); err != nil {
assetBalancesCollecor, err := newAssetBalancesCollector(p.config, p.registry)
if err != nil {
return err
}
p.registry.MustRegister(assetBalancesCollecor)

gardenCollector, err := newGardenCollector(p.config, p.registry)
if err != nil {
return err
}
p.registry.MustRegister(gardenCollector)

// Make ensure that all metrics exist when collecting and querying.
serverMetrics.InitializeMetrics(p.config.RPCServer)

// Finally, we'll launch the HTTP server that Prometheus will use to
// scape our metrics.
// scrape our metrics.
go func() {
// Use our custom prometheus registry.
promMux := http.NewServeMux()
promMux.Handle("/metrics", promhttp.HandlerFor(
reg, promhttp.HandlerOpts{
p.registry, promhttp.HandlerOpts{
EnableOpenMetrics: true,
MaxRequestsInFlight: 1,
}),
Expand All @@ -98,61 +105,3 @@ func (p *PrometheusExporter) Start() error {

return nil
}

// registerMetrics iterates through all the registered metric groups and
// attempts to register each one. If any of the MetricGroups fail to register,
// then an error will be returned.
func (p *PrometheusExporter) registerMetrics() error {
metricsMtx.Lock()
defer metricsMtx.Unlock()

for _, metricGroupFunc := range metricGroups {
metricGroup, err := metricGroupFunc(p.config)
if err != nil {
return err
}

if err := metricGroup.RegisterMetricFuncs(); err != nil {
return err
}

activeGroups[metricGroup.Name()] = metricGroup
}

return nil
}

// gauges is a map type that maps a gauge to its unique name.
type gauges map[string]*prometheus.GaugeVec // nolint:unused

// addGauge adds a new gauge vector to the map.
func (g gauges) addGauge(name, help string, labels []string) { // nolint:unused
g[name] = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: name,
Help: help,
},
labels,
)
}

// describe describes all gauges contained in the map to the given channel.
func (g gauges) describe(ch chan<- *prometheus.Desc) { // nolint:unused
for _, gauge := range g {
gauge.Describe(ch)
}
}

// collect collects all metrics of the map's gauges to the given channel.
func (g gauges) collect(ch chan<- prometheus.Metric) { // nolint:unused
for _, gauge := range g {
gauge.Collect(ch)
}
}

// reset resets all gauges in the map.
func (g gauges) reset() { // nolint:unused
for _, gauge := range g {
gauge.Reset()
}
}
16 changes: 13 additions & 3 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,16 @@ func (s *Server) RunUntilShutdown(mainErrChan <-chan error) error {
// configuration.
s.cfg.Prometheus.RPCServer = grpcServer

// Provide Prometheus collectors with access to Universe stats.
s.cfg.Prometheus.UniverseStats = s.cfg.UniverseStats

// Provide Prometheus collectors with access to the asset store.
s.cfg.Prometheus.AssetStore = s.cfg.AssetStore

// Provide Prometheus collectors with access to the asset
// minter.
s.cfg.Prometheus.AssetMinter = s.cfg.AssetMinter

promExporter, err := monitoring.NewPrometheusExporter(
&s.cfg.Prometheus,
)
Expand All @@ -321,13 +331,13 @@ func (s *Server) RunUntilShutdown(mainErrChan <-chan error) error {
err)
}

srvrLog.Infof("Prometheus exporter server listening on %v",
s.cfg.Prometheus.ListenAddr)

if err := promExporter.Start(); err != nil {
return mkErr("Unable to start prometheus exporter: %v",
err)
}

srvrLog.Infof("Prometheus exporter server listening on %v",
s.cfg.Prometheus.ListenAddr)
}

srvrLog.Infof("Taproot Asset Daemon fully active!")
Expand Down

0 comments on commit 2ca8ec8

Please sign in to comment.