Skip to content

Commit

Permalink
feat: expose rank & active set metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
MattKetmo committed Sep 14, 2023
1 parent 6c164b8 commit 53a2698
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 15 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ GLOBAL OPTIONS:
All metrics are by default prefixed by `cosmos_validator_watcher` but this can be changed through options.

Metrics (without prefix) | Description
----------------------------------------------|------------------------------------------------
-------------------------|------------------------------------------------
`block_height` | Latest known block height (all nodes mixed up)
`rank` | Rank of the validator (or 0 is not bonded)
`active_set` | Number of validators in the active set
`validated_blocks` | Number of validated blocks per validator (for a bonded validator)
`missed_blocks` | Number of missed blocks per validator (for a bonded validator)
`tracked_blocks` | Number of blocks tracked since start
Expand Down
6 changes: 6 additions & 0 deletions pkg/exporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ type ValidatorStatus struct {
Label string
Bonded bool
Signed bool
Rank int
}

func (e *Exporter) handleBlock(block *types.Block) {
Expand All @@ -91,6 +92,7 @@ func (e *Exporter) handleBlock(block *types.Block) {

e.latestBlockHeight = block.Header.Height
e.cfg.Metrics.BlockHeight.Set(float64(block.Header.Height))
e.cfg.Metrics.ActiveSet.Set(float64(len(block.LastCommit.Signatures)))
e.cfg.Metrics.TrackedBlocks.Inc()

result := BlockResult{
Expand All @@ -109,13 +111,16 @@ func (e *Exporter) handleBlock(block *types.Block) {
for _, val := range e.cfg.TrackedValidators {
bonded := false
signed := false
rank := 0
for i, sig := range block.LastCommit.Signatures {
if sig.ValidatorAddress.String() == "" {
log.Warn().Msgf("empty validator address at pos %d", i)
}
if val.Address == sig.ValidatorAddress.String() {
bonded = true
signed = !sig.Absent()
rank = i + 1
e.cfg.Metrics.Rank.WithLabelValues(val.Address, val.Name).Set(float64(rank))
}
if signed {
break
Expand All @@ -126,6 +131,7 @@ func (e *Exporter) handleBlock(block *types.Block) {
Label: val.Name,
Bonded: bonded,
Signed: signed,
Rank: rank,
})
}

Expand Down
46 changes: 32 additions & 14 deletions pkg/exporter/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import (

func TestExporter(t *testing.T) {
var (
address = "3DC4DD610817606AD4A8F9D762A068A81E8741E2"
name = "Kiln"
kilnAddress = "3DC4DD610817606AD4A8F9D762A068A81E8741E2"
kilnName = "Kiln"

miscAddress = "1234567890ABCDEF10817606AD4A8FD7620A81E4"
)

exporter := New(&Config{
Expand All @@ -30,8 +32,8 @@ func TestExporter(t *testing.T) {
ValidatorsChan: make(chan []stakingtypes.Validator),
TrackedValidators: []TrackedValidator{
{
Address: address,
Name: name,
Address: kilnAddress,
Name: kilnName,
},
},
})
Expand Down Expand Up @@ -68,7 +70,7 @@ func TestExporter(t *testing.T) {
Signatures: []types.CommitSig{
{
BlockIDFlag: types.BlockIDFlagAbsent,
ValidatorAddress: MustParseAddress(address),
ValidatorAddress: MustParseAddress(kilnAddress),
},
},
},
Expand All @@ -77,9 +79,13 @@ func TestExporter(t *testing.T) {
Header: types.Header{Height: 41},
LastCommit: &types.Commit{
Signatures: []types.CommitSig{
{
BlockIDFlag: types.BlockIDFlagAbsent,
ValidatorAddress: MustParseAddress(miscAddress),
},
{
BlockIDFlag: types.BlockIDFlagCommit,
ValidatorAddress: MustParseAddress(address),
ValidatorAddress: MustParseAddress(kilnAddress),
},
},
},
Expand All @@ -90,7 +96,11 @@ func TestExporter(t *testing.T) {
Signatures: []types.CommitSig{
{
BlockIDFlag: types.BlockIDFlagCommit,
ValidatorAddress: MustParseAddress(address),
ValidatorAddress: MustParseAddress(miscAddress),
},
{
BlockIDFlag: types.BlockIDFlagCommit,
ValidatorAddress: MustParseAddress(kilnAddress),
},
},
},
Expand All @@ -105,8 +115,8 @@ func TestExporter(t *testing.T) {
strings.Join([]string{
`#35 0/1 validators ⚪️ Kiln`,
`#40 0/1 validators ❌ Kiln`,
`#41 1/1 validators ✅ Kiln`,
`#42 1/1 validators ✅ Kiln`,
`#41 1/2 validators ✅ Kiln`,
`#42 2/2 validators ✅ Kiln`,
}, "\n")+"\n",
exporter.cfg.Writer.(*bytes.Buffer).String(),
)
Expand All @@ -115,6 +125,10 @@ func TestExporter(t *testing.T) {
`gauge:<value:42 > `,
ReadMetric(exporter.cfg.Metrics.BlockHeight),
)
assert.Equal(t,
`gauge:<value:2 > `,
ReadMetric(exporter.cfg.Metrics.ActiveSet),
)
assert.Equal(t,
`counter:<value:4 > `,
ReadMetric(exporter.cfg.Metrics.TrackedBlocks),
Expand All @@ -123,13 +137,17 @@ func TestExporter(t *testing.T) {
`counter:<value:5 > `,
ReadMetric(exporter.cfg.Metrics.SkippedBlocks),
)
assert.Equal(t,
`label:<name:"address" value:"3DC4DD610817606AD4A8F9D762A068A81E8741E2" > label:<name:"name" value:"Kiln" > gauge:<value:2 > `,
ReadMetric(exporter.cfg.Metrics.Rank.WithLabelValues(kilnAddress, kilnName)),
)
assert.Equal(t,
`label:<name:"address" value:"3DC4DD610817606AD4A8F9D762A068A81E8741E2" > label:<name:"name" value:"Kiln" > counter:<value:2 > `,
ReadMetric(exporter.cfg.Metrics.ValidatedBlocks.WithLabelValues(address, name)),
ReadMetric(exporter.cfg.Metrics.ValidatedBlocks.WithLabelValues(kilnAddress, kilnName)),
)
assert.Equal(t,
`label:<name:"address" value:"3DC4DD610817606AD4A8F9D762A068A81E8741E2" > label:<name:"name" value:"Kiln" > counter:<value:1 > `,
ReadMetric(exporter.cfg.Metrics.MissedBlocks.WithLabelValues(address, name)),
ReadMetric(exporter.cfg.Metrics.MissedBlocks.WithLabelValues(kilnAddress, kilnName)),
)
})

Expand Down Expand Up @@ -158,15 +176,15 @@ func TestExporter(t *testing.T) {

assert.Equal(t,
`label:<name:"address" value:"3DC4DD610817606AD4A8F9D762A068A81E8741E2" > label:<name:"name" value:"Kiln" > gauge:<value:42 > `,
ReadMetric(exporter.cfg.Metrics.BondedTokens.WithLabelValues(address, name)),
ReadMetric(exporter.cfg.Metrics.BondedTokens.WithLabelValues(kilnAddress, kilnName)),
)
assert.Equal(t,
`label:<name:"address" value:"3DC4DD610817606AD4A8F9D762A068A81E8741E2" > label:<name:"name" value:"Kiln" > gauge:<value:1 > `,
ReadMetric(exporter.cfg.Metrics.IsBonded.WithLabelValues(address, name)),
ReadMetric(exporter.cfg.Metrics.IsBonded.WithLabelValues(kilnAddress, kilnName)),
)
assert.Equal(t,
`label:<name:"address" value:"3DC4DD610817606AD4A8F9D762A068A81E8741E2" > label:<name:"name" value:"Kiln" > gauge:<value:0 > `,
ReadMetric(exporter.cfg.Metrics.IsJailed.WithLabelValues(address, name)),
ReadMetric(exporter.cfg.Metrics.IsJailed.WithLabelValues(kilnAddress, kilnName)),
)
})
}
19 changes: 19 additions & 0 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import "github.com/prometheus/client_golang/prometheus"
type Metrics struct {
// Exporter metrics
BlockHeight prometheus.Gauge
Rank *prometheus.GaugeVec
ActiveSet prometheus.Gauge
ValidatedBlocks *prometheus.CounterVec
MissedBlocks *prometheus.CounterVec
TrackedBlocks prometheus.Counter
Expand All @@ -27,6 +29,21 @@ func New(namespace string) *Metrics {
Help: "Latest known block height (all nodes mixed up)",
},
),
Rank: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: namespace,
Name: "rank",
Help: "Rank of the validator (or 0 is not bonded)",
},
[]string{"address", "name"},
),
ActiveSet: prometheus.NewGauge(
prometheus.GaugeOpts{
Namespace: namespace,
Name: "active_set",
Help: "Number of validators in the active set",
},
),
ValidatedBlocks: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Expand Down Expand Up @@ -100,6 +117,8 @@ func New(namespace string) *Metrics {
}

prometheus.MustRegister(metrics.BlockHeight)
prometheus.MustRegister(metrics.Rank)
prometheus.MustRegister(metrics.ActiveSet)
prometheus.MustRegister(metrics.ValidatedBlocks)
prometheus.MustRegister(metrics.MissedBlocks)
prometheus.MustRegister(metrics.TrackedBlocks)
Expand Down

0 comments on commit 53a2698

Please sign in to comment.