Skip to content

Commit 0551a3f

Browse files
authored
Merge pull request #1054 from GeorgeTsagk/prom-loadtest-metrics
Add more prometheus metrics
2 parents 30e7166 + 5a0a75c commit 0551a3f

File tree

13 files changed

+371
-8
lines changed

13 files changed

+371
-8
lines changed

dev.Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ COPY . /app
66

77
ENV CGO_ENABLED=0
88

9-
RUN make install
9+
RUN make release-install TAGS=monitoring
1010

1111
# FINAL IMAGE
1212
FROM alpine as final

monitoring/db_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+
"context"
5+
"errors"
6+
"sync"
7+
8+
"github.com/prometheus/client_golang/prometheus"
9+
)
10+
11+
const (
12+
dbSizeMetric = "total_db_size"
13+
14+
assetProofSizesHistogram = "asset_proofs_sizes"
15+
)
16+
17+
// dbCollector is a Prometheus collector that exports metrics related to the
18+
// daemon's database.
19+
type dbCollector struct {
20+
collectMx sync.Mutex
21+
22+
cfg *PrometheusConfig
23+
registry *prometheus.Registry
24+
25+
dbSize prometheus.Gauge
26+
proofSizesHistogram prometheus.Histogram
27+
}
28+
29+
func newDbCollector(cfg *PrometheusConfig,
30+
registry *prometheus.Registry) (*dbCollector, error) {
31+
32+
if cfg == nil {
33+
return nil, errors.New("db collector prometheus cfg is nil")
34+
}
35+
36+
if cfg.AssetStore == nil {
37+
return nil, errors.New("db collector asset store is nil")
38+
}
39+
40+
return &dbCollector{
41+
cfg: cfg,
42+
registry: registry,
43+
dbSize: prometheus.NewGauge(
44+
prometheus.GaugeOpts{
45+
Name: dbSizeMetric,
46+
Help: "Total size of db",
47+
},
48+
),
49+
proofSizesHistogram: newProofSizesHistogram(),
50+
}, nil
51+
}
52+
53+
// newProofSizesHistogram generates a fresh instance of the proof sizes
54+
// histogram.
55+
func newProofSizesHistogram() (h prometheus.Histogram) {
56+
return prometheus.NewHistogram(
57+
prometheus.HistogramOpts{
58+
Name: assetProofSizesHistogram,
59+
Help: "Histogram of asset proof sizes",
60+
Buckets: prometheus.ExponentialBuckets(
61+
2, 2, 32,
62+
),
63+
},
64+
)
65+
}
66+
67+
// Describe sends the super-set of all possible descriptors of metrics
68+
// collected by this Collector to the provided channel and returns once the
69+
// last descriptor has been sent.
70+
//
71+
// NOTE: Part of the prometheus.Collector interface.
72+
func (a *dbCollector) Describe(ch chan<- *prometheus.Desc) {
73+
a.collectMx.Lock()
74+
defer a.collectMx.Unlock()
75+
76+
a.dbSize.Describe(ch)
77+
a.proofSizesHistogram.Describe(ch)
78+
}
79+
80+
// Collect is called by the Prometheus registry when collecting metrics.
81+
//
82+
// NOTE: Part of the prometheus.Collector interface.
83+
func (a *dbCollector) Collect(ch chan<- prometheus.Metric) {
84+
a.collectMx.Lock()
85+
defer a.collectMx.Unlock()
86+
87+
ctxdb, cancel := context.WithTimeout(context.Background(), dbTimeout)
88+
defer cancel()
89+
90+
// Fetch the db size.
91+
dbSize, err := a.cfg.AssetStore.AssetsDBSize(ctxdb)
92+
if err != nil {
93+
log.Errorf("unable to fetch db size: %v", err)
94+
return
95+
}
96+
97+
a.dbSize.Set(float64(dbSize))
98+
99+
// Fetch all proof sizes.
100+
proofSizes, err := a.cfg.AssetStore.FetchAssetProofsSizes(ctxdb)
101+
if err != nil {
102+
log.Errorf("unable to fetch asset proofs: %v", err)
103+
return
104+
}
105+
106+
// We use the histogram in a non-standard way. Everytime we collect data
107+
// we ask the database to return all proof sizes and then we feed them
108+
// to the histogram. That's why on every different pass we need to reset
109+
// the histogram instance, in order to not duplicate data on every
110+
// prometheus pass.
111+
a.proofSizesHistogram = newProofSizesHistogram()
112+
113+
// We'll feed the proof sizes to the histogram.
114+
for _, p := range proofSizes {
115+
a.proofSizesHistogram.Observe(p.ProofFileLength)
116+
}
117+
118+
a.proofSizesHistogram.Collect(ch)
119+
a.dbSize.Collect(ch)
120+
}

monitoring/prometheus.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ func (p *PrometheusExporter) Start() error {
7474
}
7575
p.registry.MustRegister(gardenCollector)
7676

77+
dbCollector, err := newDbCollector(p.config, p.registry)
78+
if err != nil {
79+
return err
80+
}
81+
p.registry.MustRegister(dbCollector)
82+
7783
// Make ensure that all metrics exist when collecting and querying.
7884
serverMetrics.InitializeMetrics(p.config.RPCServer)
7985

tapcfg/server.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,25 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
4242
lndServices *lndclient.LndServices, enableChannelFeatures bool,
4343
mainErrChan chan<- error) (*tap.Config, error) {
4444

45-
var err error
45+
var (
46+
err error
47+
db databaseBackend
48+
dbType sqlc.BackendType
49+
)
4650

4751
// Now that we know where the database will live, we'll go ahead and
4852
// open up the default implementation of it.
49-
var db databaseBackend
5053
switch cfg.DatabaseBackend {
5154
case DatabaseBackendSqlite:
55+
dbType = sqlc.BackendTypeSqlite
56+
5257
cfgLogger.Infof("Opening sqlite3 database at: %v",
5358
cfg.Sqlite.DatabaseFileName)
5459
db, err = tapdb.NewSqliteStore(cfg.Sqlite)
5560

5661
case DatabaseBackendPostgres:
62+
dbType = sqlc.BackendTypePostgres
63+
5764
cfgLogger.Infof("Opening postgres database at: %v",
5865
cfg.Postgres.DSN(true))
5966
db, err = tapdb.NewPostgresStore(cfg.Postgres)
@@ -85,6 +92,12 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
8592
},
8693
)
8794

95+
metaDB := tapdb.NewTransactionExecutor(
96+
db, func(tx *sql.Tx) tapdb.MetaStore {
97+
return db.WithTx(tx)
98+
},
99+
)
100+
88101
addrBookDB := tapdb.NewTransactionExecutor(
89102
db, func(tx *sql.Tx) tapdb.AddrBook {
90103
return db.WithTx(tx)
@@ -94,7 +107,7 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
94107
tapdbAddrBook := tapdb.NewTapAddressBook(
95108
addrBookDB, &tapChainParams, defaultClock,
96109
)
97-
assetStore := tapdb.NewAssetStore(assetDB, defaultClock)
110+
assetStore := tapdb.NewAssetStore(assetDB, metaDB, defaultClock, dbType)
98111

99112
keyRing := tap.NewLndRpcKeyRing(lndServices)
100113
walletAnchor := tap.NewLndRpcWalletAnchor(lndServices)

tapdb/asset_minting_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,18 @@ func newAssetStoreFromDB(db *BaseDB) (*AssetMintingStore, *AssetStore) {
5454
return db.WithTx(tx)
5555
}
5656

57+
metaTxCreator := func(tx *sql.Tx) MetaStore {
58+
return db.WithTx(tx)
59+
}
60+
5761
assetMintingDB := NewTransactionExecutor(db, txCreator)
5862
assetsDB := NewTransactionExecutor(db, activeTxCreator)
63+
metaDB := NewTransactionExecutor(db, metaTxCreator)
64+
5965
testClock := clock.NewTestClock(time.Now())
6066

6167
return NewAssetMintingStore(assetMintingDB),
62-
NewAssetStore(assetsDB, testClock)
68+
NewAssetStore(assetsDB, metaDB, testClock, db.Backend())
6369
}
6470

6571
func assertBatchState(t *testing.T, batch *tapgarden.MintingBatch,

tapdb/assets_store.go

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ type (
4343
// script key.
4444
AssetProof = sqlc.FetchAssetProofsRow
4545

46+
// AssetProofSize is the asset proof size for a given asset, identified
47+
// by its script key.
48+
AssetProofSize = sqlc.FetchAssetProofsSizesRow
49+
4650
// AssetProofI is identical to AssetProof but is used for the case
4751
// where the proofs for a specific asset are fetched.
4852
AssetProofI = sqlc.FetchAssetProofRow
@@ -195,6 +199,10 @@ type ActiveAssetsStore interface {
195199
// disk.
196200
FetchAssetProofs(ctx context.Context) ([]AssetProof, error)
197201

202+
// FetchAssetsProofsSizes fetches all the asset proofs lengths that are
203+
// stored on disk.
204+
FetchAssetProofsSizes(ctx context.Context) ([]AssetProofSize, error)
205+
198206
// FetchAssetProof fetches the asset proof for a given asset identified
199207
// by its script key.
200208
FetchAssetProof(ctx context.Context,
@@ -339,6 +347,18 @@ type ActiveAssetsStore interface {
339347
assetID []byte) (sqlc.FetchAssetMetaForAssetRow, error)
340348
}
341349

350+
// MetaStore is a sub-set of the main sqlc.Querier interface that contains
351+
// methods related to metadata of the daemon.
352+
type MetaStore interface {
353+
// AssetsDBSize returns the total size of the taproot assets sqlite
354+
// database.
355+
AssetsDBSizeSqlite(ctx context.Context) (int32, error)
356+
357+
// AssetsDBSize returns the total size of the taproot assets postgres
358+
// database.
359+
AssetsDBSizePostgres(ctx context.Context) (int64, error)
360+
}
361+
342362
// AssetBalance holds a balance query result for a particular asset or all
343363
// assets tracked by this daemon.
344364
type AssetBalance struct {
@@ -378,29 +398,46 @@ type BatchedAssetStore interface {
378398
BatchedTx[ActiveAssetsStore]
379399
}
380400

401+
// BatchedMetaStore combines the MetaStore interface with the BatchedTx
402+
// interface, allowing for multiple queries to be executed in a single SQL
403+
// transaction.
404+
type BatchedMetaStore interface {
405+
MetaStore
406+
407+
BatchedTx[MetaStore]
408+
}
409+
381410
// AssetStore is used to query for the set of pending and confirmed assets.
382411
type AssetStore struct {
383412
db BatchedAssetStore
384413

414+
metaDb BatchedMetaStore
415+
385416
// eventDistributor is an event distributor that will be used to notify
386417
// subscribers about new proofs that are added to the archiver.
387418
eventDistributor *fn.EventDistributor[proof.Blob]
388419

389420
clock clock.Clock
390421

391422
txHeights *lru.Cache[chainhash.Hash, cacheableBlockHeight]
423+
424+
dbType sqlc.BackendType
392425
}
393426

394427
// NewAssetStore creates a new AssetStore from the specified BatchedAssetStore
395428
// interface.
396-
func NewAssetStore(db BatchedAssetStore, clock clock.Clock) *AssetStore {
429+
func NewAssetStore(db BatchedAssetStore, metaDB BatchedMetaStore,
430+
clock clock.Clock, dbType sqlc.BackendType) *AssetStore {
431+
397432
return &AssetStore{
398433
db: db,
434+
metaDb: metaDB,
399435
eventDistributor: fn.NewEventDistributor[proof.Blob](),
400436
clock: clock,
401437
txHeights: lru.NewCache[chainhash.Hash, cacheableBlockHeight](
402438
10_000,
403439
),
440+
dbType: dbType,
404441
}
405442
}
406443

@@ -1171,6 +1208,38 @@ func (a *AssetStore) FetchManagedUTXOs(ctx context.Context) (
11711208
return managedUtxos, nil
11721209
}
11731210

1211+
// FetchAssetProofsSizes fetches the sizes of the proofs in the db.
1212+
func (a *AssetStore) FetchAssetProofsSizes(
1213+
ctx context.Context) ([]AssetProofSize, error) {
1214+
1215+
var pSizes []AssetProofSize
1216+
1217+
readOpts := NewAssetStoreReadTx()
1218+
dbErr := a.db.ExecTx(ctx, &readOpts, func(q ActiveAssetsStore) error {
1219+
proofSizes, err := q.FetchAssetProofsSizes(ctx)
1220+
if err != nil {
1221+
return err
1222+
}
1223+
1224+
for _, v := range proofSizes {
1225+
pSizes = append(
1226+
pSizes, AssetProofSize{
1227+
ScriptKey: v.ScriptKey,
1228+
ProofFileLength: v.ProofFileLength,
1229+
},
1230+
)
1231+
}
1232+
1233+
return nil
1234+
})
1235+
1236+
if dbErr != nil {
1237+
return nil, dbErr
1238+
}
1239+
1240+
return pSizes, nil
1241+
}
1242+
11741243
// FetchAssetProofs returns the latest proof file for either the set of target
11751244
// assets, or all assets if no script keys for an asset are passed in.
11761245
//
@@ -3280,6 +3349,45 @@ func (a *AssetStore) FetchAssetMetaForAsset(ctx context.Context,
32803349
return assetMeta, nil
32813350
}
32823351

3352+
// AssetsDBSize returns the total size of the taproot assets database.
3353+
func (a *AssetStore) AssetsDBSize(ctx context.Context) (int64, error) {
3354+
var totalSize int64
3355+
3356+
readOpts := NewAssetStoreReadTx()
3357+
dbErr := a.metaDb.ExecTx(ctx, &readOpts, func(q MetaStore) error {
3358+
var (
3359+
size int64
3360+
err error
3361+
)
3362+
switch a.dbType {
3363+
case sqlc.BackendTypePostgres:
3364+
size, err = q.AssetsDBSizePostgres(ctx)
3365+
3366+
case sqlc.BackendTypeSqlite:
3367+
var res int32
3368+
res, err = q.AssetsDBSizeSqlite(ctx)
3369+
size = int64(res)
3370+
3371+
default:
3372+
return fmt.Errorf("unsupported db backend type")
3373+
}
3374+
3375+
if err != nil {
3376+
return err
3377+
}
3378+
3379+
totalSize = size
3380+
3381+
return nil
3382+
})
3383+
3384+
if dbErr != nil {
3385+
return 0, dbErr
3386+
}
3387+
3388+
return totalSize, nil
3389+
}
3390+
32833391
// FetchAssetMetaByHash attempts to fetch an asset meta based on an asset hash.
32843392
func (a *AssetStore) FetchAssetMetaByHash(ctx context.Context,
32853393
metaHash [asset.MetaHashLen]byte) (*proof.MetaReveal, error) {

0 commit comments

Comments
 (0)