Skip to content

Commit 732a90c

Browse files
authored
Merge pull request #716 from GeorgeTsagk/tapd-metrics-updated
Add enhanced prometheus metrics for tapd
2 parents c61d19f + bbcd35d commit 732a90c

File tree

7 files changed

+428
-118
lines changed

7 files changed

+428
-118
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package monitoring
2+
3+
import (
4+
"context"
5+
"errors"
6+
"sync"
7+
8+
"github.com/prometheus/client_golang/prometheus"
9+
)
10+
11+
// assetBalancesCollector is a Prometheus collector that exports the balances
12+
// of all taproot assets.
13+
type assetBalancesCollector struct {
14+
collectMx sync.Mutex
15+
16+
cfg *PrometheusConfig
17+
registry *prometheus.Registry
18+
19+
balancesVec *prometheus.GaugeVec
20+
21+
utxosVec *prometheus.GaugeVec
22+
}
23+
24+
func newAssetBalancesCollector(cfg *PrometheusConfig,
25+
registry *prometheus.Registry) (*assetBalancesCollector, error) {
26+
27+
if cfg == nil {
28+
return nil, errors.New("asset collector prometheus cfg is nil")
29+
}
30+
31+
if cfg.AssetStore == nil {
32+
return nil, errors.New("asset collector asset store is nil")
33+
}
34+
35+
return &assetBalancesCollector{
36+
cfg: cfg,
37+
registry: registry,
38+
balancesVec: prometheus.NewGaugeVec(
39+
prometheus.GaugeOpts{
40+
Name: "asset_balances",
41+
Help: "Balances of all taproot assets",
42+
},
43+
[]string{"asset_name"},
44+
),
45+
utxosVec: prometheus.NewGaugeVec(
46+
prometheus.GaugeOpts{
47+
Name: "utxos_assets_held",
48+
Help: "Number of UTXOs used for taproot assets",
49+
},
50+
[]string{"outpoint"},
51+
),
52+
}, nil
53+
}
54+
55+
// Describe sends the super-set of all possible descriptors of metrics
56+
// collected by this Collector to the provided channel and returns once the
57+
// last descriptor has been sent.
58+
//
59+
// NOTE: Part of the prometheus.Collector interface.
60+
func (a *assetBalancesCollector) Describe(ch chan<- *prometheus.Desc) {
61+
a.collectMx.Lock()
62+
defer a.collectMx.Unlock()
63+
64+
a.balancesVec.Describe(ch)
65+
a.utxosVec.Describe(ch)
66+
}
67+
68+
// Collect is called by the Prometheus registry when collecting metrics.
69+
//
70+
// NOTE: Part of the prometheus.Collector interface.
71+
func (a *assetBalancesCollector) Collect(ch chan<- prometheus.Metric) {
72+
a.collectMx.Lock()
73+
defer a.collectMx.Unlock()
74+
75+
ctxdb, cancel := context.WithTimeout(context.Background(), dbTimeout)
76+
defer cancel()
77+
78+
assets, err := a.cfg.AssetStore.FetchAllAssets(ctxdb, false, false, nil)
79+
if err != nil {
80+
log.Errorf("unable to fetch assets: %v", err)
81+
return
82+
}
83+
84+
utxos, err := a.cfg.AssetStore.FetchManagedUTXOs(ctxdb)
85+
if err != nil {
86+
log.Errorf("unable to fetch utxos: %v", err)
87+
return
88+
}
89+
90+
a.utxosVec.Reset()
91+
a.balancesVec.Reset()
92+
93+
utxoMap := make(map[string]prometheus.Gauge)
94+
95+
for _, utxo := range utxos {
96+
utxoOutpoint := utxo.OutPoint.String()
97+
utxoMap[utxoOutpoint] = a.utxosVec.WithLabelValues(utxoOutpoint)
98+
}
99+
100+
for _, asset := range assets {
101+
a.balancesVec.WithLabelValues(asset.Tag).
102+
Set(float64(asset.Amount))
103+
104+
utxoGauge, ok := utxoMap[asset.AnchorOutpoint.String()]
105+
if !ok {
106+
continue
107+
}
108+
109+
utxoGauge.Inc()
110+
}
111+
112+
a.balancesVec.Collect(ch)
113+
a.utxosVec.Collect(ch)
114+
}

monitoring/asset_collector.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package monitoring
2+
3+
import (
4+
"context"
5+
"errors"
6+
"sync"
7+
8+
"github.com/prometheus/client_golang/prometheus"
9+
)
10+
11+
const (
12+
numAssetsMintedMetric = "num_assets_minted"
13+
14+
numTotalGroupsMetric = "num_total_groups"
15+
16+
numTotalSyncsMetric = "num_total_syncs"
17+
18+
numTotalProofsMetric = "num_total_proofs"
19+
)
20+
21+
// universeStatsCollector is a Prometheus collector that exports the stats of
22+
// the universe.
23+
type universeStatsCollector struct {
24+
collectMx sync.Mutex
25+
26+
cfg *PrometheusConfig
27+
registry *prometheus.Registry
28+
29+
gauges map[string]prometheus.Gauge
30+
}
31+
32+
func newUniverseStatsCollector(cfg *PrometheusConfig,
33+
registry *prometheus.Registry) (*universeStatsCollector, error) {
34+
35+
if cfg == nil {
36+
return nil, errors.New("universe stats collector prometheus " +
37+
"cfg is nil")
38+
}
39+
40+
if cfg.UniverseStats == nil {
41+
return nil, errors.New("universe stats collector universe " +
42+
"stats is nil")
43+
}
44+
45+
gaugesMap := map[string]prometheus.Gauge{
46+
numAssetsMintedMetric: prometheus.NewGauge(
47+
prometheus.GaugeOpts{
48+
Name: numAssetsMintedMetric,
49+
Help: "Total number of assets minted",
50+
},
51+
),
52+
numTotalGroupsMetric: prometheus.NewGauge(
53+
prometheus.GaugeOpts{
54+
Name: numTotalGroupsMetric,
55+
Help: "Total number of groups",
56+
},
57+
),
58+
numTotalSyncsMetric: prometheus.NewGauge(
59+
prometheus.GaugeOpts{
60+
Name: numTotalSyncsMetric,
61+
Help: "Total number of syncs",
62+
},
63+
),
64+
numTotalProofsMetric: prometheus.NewGauge(
65+
prometheus.GaugeOpts{
66+
Name: numTotalProofsMetric,
67+
Help: "Total number of proofs",
68+
},
69+
),
70+
}
71+
72+
return &universeStatsCollector{
73+
cfg: cfg,
74+
registry: registry,
75+
gauges: gaugesMap,
76+
}, nil
77+
}
78+
79+
// Describe sends the super-set of all possible descriptors of metrics
80+
// collected by this Collector to the provided channel and returns once the
81+
// last descriptor has been sent.
82+
//
83+
// NOTE: Part of the prometheus.Collector interface.
84+
func (a *universeStatsCollector) Describe(ch chan<- *prometheus.Desc) {
85+
a.collectMx.Lock()
86+
defer a.collectMx.Unlock()
87+
88+
for _, gauge := range a.gauges {
89+
gauge.Describe(ch)
90+
}
91+
}
92+
93+
// Collect is called by the Prometheus registry when collecting metrics.
94+
//
95+
// NOTE: Part of the prometheus.Collector interface.
96+
func (a *universeStatsCollector) Collect(ch chan<- prometheus.Metric) {
97+
a.collectMx.Lock()
98+
defer a.collectMx.Unlock()
99+
100+
ctx, cancel := context.WithTimeout(context.Background(), dbTimeout)
101+
defer cancel()
102+
103+
universeStats, err := a.cfg.UniverseStats.AggregateSyncStats(ctx)
104+
if err != nil {
105+
log.Errorf("unable to get aggregate universe stats: %v", err)
106+
return
107+
}
108+
109+
a.gauges[numAssetsMintedMetric].Set(
110+
float64(universeStats.NumTotalAssets),
111+
)
112+
113+
a.gauges[numTotalGroupsMetric].Set(
114+
float64(universeStats.NumTotalGroups),
115+
)
116+
117+
a.gauges[numTotalSyncsMetric].Set(
118+
float64(universeStats.NumTotalSyncs),
119+
)
120+
121+
a.gauges[numTotalProofsMetric].Set(
122+
float64(universeStats.NumTotalProofs),
123+
)
124+
125+
for _, gauge := range a.gauges {
126+
gauge.Collect(ch)
127+
}
128+
}

monitoring/config.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package monitoring
22

3-
import "google.golang.org/grpc"
3+
import (
4+
"github.com/lightninglabs/taproot-assets/tapdb"
5+
"github.com/lightninglabs/taproot-assets/tapgarden"
6+
"github.com/lightninglabs/taproot-assets/universe"
7+
"google.golang.org/grpc"
8+
)
49

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

25+
// UniverseStats is used to collect any stats that are relevant to the
26+
// universe.
27+
UniverseStats universe.Telemetry
28+
29+
// AssetStore is used to collect any stats that are relevant to the
30+
// asset store.
31+
AssetStore *tapdb.AssetStore
32+
33+
// AssetMinter is used to collect any stats that are relevant to the
34+
// asset minter.
35+
AssetMinter tapgarden.Planter
36+
2037
// PerfHistograms indicates if the additional histogram information for
2138
// latency, and handling time of gRPC calls should be enabled. This
2239
// generates additional data, and consume more memory for the

monitoring/garden_collector.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package monitoring
2+
3+
import (
4+
"errors"
5+
"sync"
6+
7+
"github.com/lightninglabs/taproot-assets/tapgarden"
8+
"github.com/prometheus/client_golang/prometheus"
9+
)
10+
11+
// assetBalancesCollector is a Prometheus collector that exports the balances
12+
// of all taproot assets.
13+
type gardenCollector struct {
14+
collectMx sync.Mutex
15+
16+
cfg *PrometheusConfig
17+
registry *prometheus.Registry
18+
19+
pendingBatches *prometheus.GaugeVec
20+
completedBatches prometheus.Gauge
21+
}
22+
23+
func newGardenCollector(cfg *PrometheusConfig,
24+
registry *prometheus.Registry) (*gardenCollector, error) {
25+
26+
if cfg == nil {
27+
return nil, errors.New("garden collector prometheus cfg is nil")
28+
}
29+
30+
if cfg.AssetStore == nil {
31+
return nil, errors.New("garden collector asset store is nil")
32+
}
33+
34+
return &gardenCollector{
35+
cfg: cfg,
36+
registry: registry,
37+
pendingBatches: prometheus.NewGaugeVec(
38+
prometheus.GaugeOpts{
39+
Name: "mint_batches",
40+
Help: "Batched mint transactions",
41+
},
42+
[]string{"batch_pubkey"},
43+
),
44+
completedBatches: prometheus.NewGauge(
45+
prometheus.GaugeOpts{
46+
Name: "completed_batches",
47+
Help: "Total number of completed mint batches",
48+
},
49+
),
50+
}, nil
51+
}
52+
53+
// Describe sends the super-set of all possible descriptors of metrics
54+
// collected by this Collector to the provided channel and returns once the
55+
// last descriptor has been sent.
56+
//
57+
// NOTE: Part of the prometheus.Collector interface.
58+
func (a *gardenCollector) Describe(ch chan<- *prometheus.Desc) {
59+
a.collectMx.Lock()
60+
defer a.collectMx.Unlock()
61+
62+
a.pendingBatches.Describe(ch)
63+
a.completedBatches.Describe(ch)
64+
}
65+
66+
// Collect is called by the Prometheus registry when collecting metrics.
67+
//
68+
// NOTE: Part of the prometheus.Collector interface.
69+
func (a *gardenCollector) Collect(ch chan<- prometheus.Metric) {
70+
a.collectMx.Lock()
71+
defer a.collectMx.Unlock()
72+
73+
a.completedBatches.Set(0)
74+
75+
// Get the number of pending batches.
76+
batches, err := a.cfg.AssetMinter.ListBatches(nil)
77+
if err != nil {
78+
log.Errorf("unable to list batches: %v", err)
79+
return
80+
}
81+
82+
completed := 0
83+
84+
for _, batch := range batches {
85+
state := batch.State()
86+
87+
switch {
88+
case state == tapgarden.BatchStatePending ||
89+
state == tapgarden.BatchStateFrozen ||
90+
state == tapgarden.BatchStateCommitted ||
91+
state == tapgarden.BatchStateBroadcast ||
92+
state == tapgarden.BatchStateConfirmed:
93+
94+
if state == tapgarden.BatchStatePending {
95+
a.pendingBatches.WithLabelValues(
96+
batch.BatchKey.PubKey.X().String(),
97+
).Set(
98+
float64(len(batch.Seedlings)),
99+
)
100+
}
101+
102+
case state == tapgarden.BatchStateFinalized ||
103+
state == tapgarden.BatchStateSeedlingCancelled ||
104+
state == tapgarden.BatchStateSproutCancelled:
105+
106+
a.pendingBatches.DeleteLabelValues(
107+
batch.BatchKey.PubKey.X().String(),
108+
)
109+
110+
if state == tapgarden.BatchStateFinalized {
111+
completed += 1
112+
}
113+
}
114+
}
115+
116+
a.completedBatches.Set(float64(completed))
117+
118+
a.pendingBatches.Collect(ch)
119+
a.completedBatches.Collect(ch)
120+
}

0 commit comments

Comments
 (0)