Skip to content

Commit 51dae0e

Browse files
gupadhyayaGanesha Upadhyaya
andauthored
add prometheus metric support (#1432)
Fixes #1393 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Integrated metrics tracking for block synchronization, block management, P2P networking, and block execution. - Added block size calculation to provide insights into block data. - **Enhancements** - Improved node configuration with new instrumentation options. - Enhanced existing functions to utilize metrics, improving observability. - **Bug Fixes** - Adjusted test cases to align with the updated metrics integration. - **Documentation** - Updated internal documentation to reflect metrics integration in various components. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ganesha Upadhyaya <gupadhyaya@Ganeshas-MacBook-Pro-2.local>
1 parent 9163b34 commit 51dae0e

23 files changed

Lines changed: 435 additions & 38 deletions

block/block_sync.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ func NewBlockSyncService(ctx context.Context, store ds.TxnDatastore, conf config
5757
if !ok {
5858
return nil, errors.New("failed to access the datastore")
5959
}
60-
ss, err := goheaderstore.NewStore[*types.Block](storeBatch, goheaderstore.WithStorePrefix("blockSync"))
60+
ss, err := goheaderstore.NewStore[*types.Block](
61+
storeBatch,
62+
goheaderstore.WithStorePrefix("blockSync"),
63+
goheaderstore.WithMetrics(),
64+
)
6165
if err != nil {
6266
return nil, fmt.Errorf("failed to initialize the block store: %w", err)
6367
}
@@ -129,6 +133,7 @@ func (bSyncService *BlockSyncService) Start() error {
129133
ps,
130134
pubsub.DefaultMsgIdFn,
131135
goheaderp2p.WithSubscriberNetworkID(chainIDBlock),
136+
goheaderp2p.WithSubscriberMetrics(),
132137
)
133138
if err != nil {
134139
return err
@@ -229,6 +234,7 @@ func newBlockP2PServer(
229234
) (*goheaderp2p.ExchangeServer[*types.Block], error) {
230235
opts = append(opts,
231236
goheaderp2p.WithNetworkID[goheaderp2p.ServerParameters](network),
237+
goheaderp2p.WithMetrics[goheaderp2p.ServerParameters](),
232238
)
233239
return goheaderp2p.NewExchangeServer[*types.Block](host, store, opts...)
234240
}
@@ -243,6 +249,7 @@ func newBlockP2PExchange(
243249
opts = append(opts,
244250
goheaderp2p.WithNetworkID[goheaderp2p.ClientParameters](network),
245251
goheaderp2p.WithChainID(chainID),
252+
goheaderp2p.WithMetrics[goheaderp2p.ClientParameters](),
246253
)
247254
return goheaderp2p.NewExchange[*types.Block](host, peers, conngater, opts...)
248255
}
@@ -254,6 +261,9 @@ func newBlockSyncer(
254261
sub header.Subscriber[*types.Block],
255262
opts []goheadersync.Option,
256263
) (*goheadersync.Syncer[*types.Block], error) {
264+
opts = append(opts,
265+
goheadersync.WithMetrics(),
266+
)
257267
return goheadersync.NewSyncer[*types.Block](ex, store, sub, opts...)
258268
}
259269

block/header_sync.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ func NewHeaderSyncService(ctx context.Context, store ds.TxnDatastore, conf confi
5858
if !ok {
5959
return nil, errors.New("failed to access the datastore")
6060
}
61-
ss, err := goheaderstore.NewStore[*types.SignedHeader](storeBatch, goheaderstore.WithStorePrefix("headerSync"))
61+
ss, err := goheaderstore.NewStore[*types.SignedHeader](
62+
storeBatch,
63+
goheaderstore.WithStorePrefix("headerSync"),
64+
goheaderstore.WithMetrics(),
65+
)
6266
if err != nil {
6367
return nil, fmt.Errorf("failed to initialize the header store: %w", err)
6468
}
@@ -127,6 +131,7 @@ func (hSyncService *HeaderSyncService) Start() error {
127131
ps,
128132
pubsub.DefaultMsgIdFn,
129133
goheaderp2p.WithSubscriberNetworkID(hSyncService.genesis.ChainID),
134+
goheaderp2p.WithSubscriberMetrics(),
130135
)
131136
if err != nil {
132137
return err
@@ -226,6 +231,7 @@ func newP2PServer(
226231
) (*goheaderp2p.ExchangeServer[*types.SignedHeader], error) {
227232
opts = append(opts,
228233
goheaderp2p.WithNetworkID[goheaderp2p.ServerParameters](network),
234+
goheaderp2p.WithMetrics[goheaderp2p.ServerParameters](),
229235
)
230236
return goheaderp2p.NewExchangeServer[*types.SignedHeader](host, store, opts...)
231237
}
@@ -240,6 +246,7 @@ func newP2PExchange(
240246
opts = append(opts,
241247
goheaderp2p.WithNetworkID[goheaderp2p.ClientParameters](network),
242248
goheaderp2p.WithChainID(chainID),
249+
goheaderp2p.WithMetrics[goheaderp2p.ClientParameters](),
243250
)
244251

245252
return goheaderp2p.NewExchange[*types.SignedHeader](host, peers, conngater, opts...)
@@ -252,6 +259,9 @@ func newSyncer(
252259
sub header.Subscriber[*types.SignedHeader],
253260
opts []goheadersync.Option,
254261
) (*goheadersync.Syncer[*types.SignedHeader], error) {
262+
opts = append(opts,
263+
goheadersync.WithMetrics(),
264+
)
255265
return goheadersync.NewSyncer[*types.SignedHeader](ex, store, sub, opts...)
256266
}
257267

block/manager.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ type Manager struct {
9797
doneBuildingBlock chan struct{}
9898

9999
pendingBlocks *PendingBlocks
100+
101+
// for reporting metrics
102+
metrics *Metrics
100103
}
101104

102105
// getInitialState tries to load lastState from Store, and if it's not available it reads GenesisDoc.
@@ -120,6 +123,8 @@ func NewManager(
120123
eventBus *cmtypes.EventBus,
121124
logger log.Logger,
122125
blockStore *goheaderstore.Store[*types.Block],
126+
seqMetrics *Metrics,
127+
execMetrics *state.Metrics,
123128
) (*Manager, error) {
124129
s, err := getInitialState(store, genesis)
125130
if err != nil {
@@ -148,7 +153,7 @@ func NewManager(
148153
return nil, err
149154
}
150155

151-
exec := state.NewBlockExecutor(proposerAddress, genesis.ChainID, mempool, proxyApp, eventBus, logger)
156+
exec := state.NewBlockExecutor(proposerAddress, genesis.ChainID, mempool, proxyApp, eventBus, logger, execMetrics)
152157
if s.LastBlockHeight+1 == uint64(genesis.InitialHeight) {
153158
res, err := exec.InitChain(genesis)
154159
if err != nil {
@@ -192,6 +197,7 @@ func NewManager(
192197
doneBuildingBlock: make(chan struct{}),
193198
buildingBlock: false,
194199
pendingBlocks: NewPendingBlocks(),
200+
metrics: seqMetrics,
195201
}
196202
return agg, nil
197203
}
@@ -780,6 +786,7 @@ func (m *Manager) publishBlock(ctx context.Context) error {
780786
if err != nil {
781787
return err
782788
}
789+
m.recordMetrics(block)
783790
// Check for shut down event prior to sending the header and block to
784791
// their respective channels. The reason for checking for the shutdown
785792
// event separately is due to the inconsistent nature of the select
@@ -801,6 +808,13 @@ func (m *Manager) publishBlock(ctx context.Context) error {
801808
return nil
802809
}
803810

811+
func (m *Manager) recordMetrics(block *types.Block) {
812+
m.metrics.NumTxs.Set(float64(len(block.Data.Txs)))
813+
m.metrics.TotalTxs.Add(float64(len(block.Data.Txs)))
814+
m.metrics.BlockSizeBytes.Set(float64(block.Size()))
815+
m.metrics.CommittedHeight.Set(float64(block.Height()))
816+
}
817+
804818
func (m *Manager) submitBlocksToDA(ctx context.Context) error {
805819
submitted := false
806820
backoff := initialBackoff
@@ -849,6 +863,7 @@ func (m *Manager) updateState(s types.State) error {
849863
return err
850864
}
851865
m.lastState = s
866+
m.metrics.Height.Set(float64(s.LastBlockHeight))
852867
return nil
853868
}
854869

block/manager_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
goDATest "github.com/rollkit/go-da/test"
1515
"github.com/rollkit/rollkit/config"
1616
"github.com/rollkit/rollkit/da"
17+
"github.com/rollkit/rollkit/state"
1718
"github.com/rollkit/rollkit/store"
1819
test "github.com/rollkit/rollkit/test/log"
1920
"github.com/rollkit/rollkit/types"
@@ -78,7 +79,7 @@ func TestInitialState(t *testing.T) {
7879
assert := assert.New(t)
7980
logger := test.NewFileLoggerCustom(t, test.TempLogFileName(t, c.name))
8081
dalc := &da.DAClient{DA: goDATest.NewDummyDA(), GasPrice: -1, Logger: logger}
81-
agg, err := NewManager(key, conf, c.genesis, c.store, nil, nil, dalc, nil, logger, nil)
82+
agg, err := NewManager(key, conf, c.genesis, c.store, nil, nil, dalc, nil, logger, nil, NopMetrics(), state.NopMetrics())
8283
assert.NoError(err)
8384
assert.NotNil(agg)
8485
agg.lastStateMtx.RLock()

block/metrics.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package block
2+
3+
import (
4+
"github.com/go-kit/kit/metrics"
5+
"github.com/go-kit/kit/metrics/discard"
6+
"github.com/go-kit/kit/metrics/prometheus"
7+
stdprometheus "github.com/prometheus/client_golang/prometheus"
8+
)
9+
10+
const (
11+
// MetricsSubsystem is a subsystem shared by all metrics exposed by this
12+
// package.
13+
MetricsSubsystem = "sequencer"
14+
)
15+
16+
// Metrics contains metrics exposed by this package.
17+
type Metrics struct {
18+
// Height of the chain.
19+
Height metrics.Gauge
20+
21+
// Number of transactions.
22+
NumTxs metrics.Gauge
23+
// Size of the block.
24+
BlockSizeBytes metrics.Gauge
25+
// Total number of transactions.
26+
TotalTxs metrics.Gauge
27+
// The latest block height.
28+
CommittedHeight metrics.Gauge `metrics_name:"latest_block_height"`
29+
}
30+
31+
// PrometheusMetrics returns Metrics build using Prometheus client library.
32+
// Optionally, labels can be provided along with their values ("foo",
33+
// "fooValue").
34+
func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
35+
labels := []string{}
36+
for i := 0; i < len(labelsAndValues); i += 2 {
37+
labels = append(labels, labelsAndValues[i])
38+
}
39+
return &Metrics{
40+
Height: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
41+
Namespace: namespace,
42+
Subsystem: MetricsSubsystem,
43+
Name: "height",
44+
Help: "Height of the chain.",
45+
}, labels).With(labelsAndValues...),
46+
NumTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
47+
Namespace: namespace,
48+
Subsystem: MetricsSubsystem,
49+
Name: "num_txs",
50+
Help: "Number of transactions.",
51+
}, labels).With(labelsAndValues...),
52+
BlockSizeBytes: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
53+
Namespace: namespace,
54+
Subsystem: MetricsSubsystem,
55+
Name: "block_size_bytes",
56+
Help: "Size of the block.",
57+
}, labels).With(labelsAndValues...),
58+
TotalTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
59+
Namespace: namespace,
60+
Subsystem: MetricsSubsystem,
61+
Name: "total_txs",
62+
Help: "Total number of transactions.",
63+
}, labels).With(labelsAndValues...),
64+
CommittedHeight: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
65+
Namespace: namespace,
66+
Subsystem: MetricsSubsystem,
67+
Name: "latest_block_height",
68+
Help: "The latest block height.",
69+
}, labels).With(labelsAndValues...),
70+
}
71+
}
72+
73+
// NopMetrics returns no-op Metrics.
74+
func NopMetrics() *Metrics {
75+
return &Metrics{
76+
Height: discard.NewGauge(),
77+
NumTxs: discard.NewGauge(),
78+
BlockSizeBytes: discard.NewGauge(),
79+
TotalTxs: discard.NewGauge(),
80+
CommittedHeight: discard.NewGauge(),
81+
}
82+
}

config/config.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ type NodeConfig struct {
3434
DAAddress string `mapstructure:"da_address"`
3535
Light bool `mapstructure:"light"`
3636
HeaderConfig `mapstructure:",squash"`
37-
LazyAggregator bool `mapstructure:"lazy_aggregator"`
38-
DAGasPrice float64 `mapstructure:"da_gas_price"`
37+
LazyAggregator bool `mapstructure:"lazy_aggregator"`
38+
Instrumentation *cmcfg.InstrumentationConfig `mapstructure:"instrumentation"`
39+
DAGasPrice float64 `mapstructure:"da_gas_price"`
3940
}
4041

4142
// HeaderConfig allows node to pass the initial trusted header hash to start the header exchange service
@@ -74,6 +75,9 @@ func GetNodeConfig(nodeConf *NodeConfig, cmConf *cmcfg.Config) {
7475
nodeConf.RPC.TLSCertFile = cmConf.RPC.TLSCertFile
7576
nodeConf.RPC.TLSKeyFile = cmConf.RPC.TLSKeyFile
7677
}
78+
if cmConf.Instrumentation != nil {
79+
nodeConf.Instrumentation = cmConf.Instrumentation
80+
}
7781
}
7882
}
7983

config/defaults.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package config
22

33
import (
44
"time"
5+
6+
"github.com/cometbft/cometbft/config"
57
)
68

79
const (
@@ -30,4 +32,5 @@ var DefaultNodeConfig = NodeConfig{
3032
HeaderConfig: HeaderConfig{
3133
TrustedHash: "",
3234
},
35+
Instrumentation: config.DefaultInstrumentationConfig(),
3336
}

0 commit comments

Comments
 (0)