diff --git a/monitoring/config.go b/monitoring/config.go index d7f7c0b77..53dd37381 100644 --- a/monitoring/config.go +++ b/monitoring/config.go @@ -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 @@ -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 diff --git a/monitoring/interface.go b/monitoring/interface.go deleted file mode 100644 index 0b9151315..000000000 --- a/monitoring/interface.go +++ /dev/null @@ -1,29 +0,0 @@ -package monitoring - -import "github.com/prometheus/client_golang/prometheus" - -// metricGroupFactory is a factory method that given the primary prometheus -// config, will create a new MetricGroup that will be managed by the main -// PrometheusExporter. -type metricGroupFactory func(*PrometheusConfig) (MetricGroup, error) - -// MetricGroup is the primary interface of this package. The main exporter (in -// this case the PrometheusExporter), will manage these directly, ensuring that -// all MetricGroups are registered before the main prometheus exporter starts -// and any additional tracing is added. -type MetricGroup interface { - // Collector is the embedded interface that forces every MetricGroup to - // also be a collector. - prometheus.Collector - - // Name is the name of the metric group. When exported to prometheus, - // it's expected that all metric under this group have the same prefix. - Name() string - - // RegisterMetricFuncs signals to the underlying hybrid collector that - // it should register all metrics that it aims to export with the - // global Prometheus registry. Rather than using the series of - // "MustRegister" directives, implementers of this interface should - // instead propagate back any errors related to metric registration. - RegisterMetricFuncs() error -} diff --git a/monitoring/prometheus.go b/monitoring/prometheus.go index c19dd647b..5f3f2d00d 100644 --- a/monitoring/prometheus.go +++ b/monitoring/prometheus.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "sync" "time" //nolint:lll @@ -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 @@ -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, }), @@ -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() - } -} diff --git a/server.go b/server.go index fd69e1558..910277ed8 100644 --- a/server.go +++ b/server.go @@ -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, ) @@ -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!")