From a090650446242147ae38df4aafdfcde62714a098 Mon Sep 17 00:00:00 2001 From: kasey Date: Mon, 3 May 2021 17:24:27 -0500 Subject: [PATCH] fixes #8848 -- scrape validator_(total|active) (#8858) fixes #8848 -- scrape validator_total, validator_active --- shared/clientstats/BUILD.bazel | 1 + shared/clientstats/scrapers.go | 20 +++++++++- shared/clientstats/scrapers_test.go | 61 ++++++++++++++++++++++++++++- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/shared/clientstats/BUILD.bazel b/shared/clientstats/BUILD.bazel index 9cbda68e9f37..c1c709f2d355 100644 --- a/shared/clientstats/BUILD.bazel +++ b/shared/clientstats/BUILD.bazel @@ -14,6 +14,7 @@ go_library( deps = [ "@com_github_prometheus_client_model//go:go_default_library", "@com_github_prometheus_prom2json//:go_default_library", + "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", ], ) diff --git a/shared/clientstats/scrapers.go b/shared/clientstats/scrapers.go index 6c44f92bd5fa..ef7bdd26e207 100644 --- a/shared/clientstats/scrapers.go +++ b/shared/clientstats/scrapers.go @@ -11,6 +11,7 @@ import ( dto "github.com/prometheus/client_model/go" "github.com/prometheus/prom2json" + eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" log "github.com/sirupsen/logrus" ) @@ -228,7 +229,12 @@ func populateBeaconNodeStats(pf metricMap) (BeaconNodeStats, error) { return bs, nil } -func populateValidatorStats(pf map[string]*dto.MetricFamily) (ValidatorStats, error) { +func statusIsActive(statusCode int64) bool { + s := eth.ValidatorStatus(statusCode) + return s.String() == "ACTIVE" +} + +func populateValidatorStats(pf metricMap) (ValidatorStats, error) { var err error vs := ValidatorStats{} vs.CommonStats, err = populateCommonStats(pf) @@ -236,5 +242,17 @@ func populateValidatorStats(pf map[string]*dto.MetricFamily) (ValidatorStats, er return vs, err } vs.APIMessage = populateAPIMessage(ValidatorProcessName) + + f, err := pf.getFamily("validator_statuses") + if err != nil { + return vs, err + } + for _, m := range f.Metric { + if statusIsActive(int64(m.Gauge.GetValue())) { + vs.ValidatorActive += 1 + } + vs.ValidatorTotal += 1 + } + return vs, nil } diff --git a/shared/clientstats/scrapers_test.go b/shared/clientstats/scrapers_test.go index b21e474ee6d0..71715e956943 100644 --- a/shared/clientstats/scrapers_test.go +++ b/shared/clientstats/scrapers_test.go @@ -65,7 +65,7 @@ func TestFalseEth2Synced(t *testing.T) { func TestValidatorScraper(t *testing.T) { vScraper := validatorScraper{} - vScraper.tripper = &mockRT{body: prometheusTestBody} + vScraper.tripper = &mockRT{body: statusFixtureOneOfEach + prometheusTestBody} r, err := vScraper.Scrape() assert.NoError(t, err, "Unexpected error calling validatorScraper.Scrape") vs := &ValidatorStats{} @@ -77,6 +77,34 @@ func TestValidatorScraper(t *testing.T) { assert.Equal(t, int64(1619586241), vs.ClientBuild) assert.Equal(t, "v1.3.8-hotfix+6c0942", vs.ClientVersion) assert.Equal(t, "prysm", vs.ClientName) + assert.Equal(t, int64(7), vs.ValidatorTotal) + assert.Equal(t, int64(1), vs.ValidatorActive) +} + +func TestValidatorScraperAllActive(t *testing.T) { + vScraper := validatorScraper{} + vScraper.tripper = &mockRT{body: statusFixtureAllActive + prometheusTestBody} + r, err := vScraper.Scrape() + assert.NoError(t, err, "Unexpected error calling validatorScraper.Scrape") + vs := &ValidatorStats{} + err = json.NewDecoder(r).Decode(vs) + assert.NoError(t, err, "Unexpected error decoding result of validatorScraper.Scrape") + // CommonStats + assert.Equal(t, int64(4), vs.ValidatorTotal) + assert.Equal(t, int64(4), vs.ValidatorActive) +} + +func TestValidatorScraperNoneActive(t *testing.T) { + vScraper := validatorScraper{} + vScraper.tripper = &mockRT{body: statusFixtureNoneActive + prometheusTestBody} + r, err := vScraper.Scrape() + assert.NoError(t, err, "Unexpected error calling validatorScraper.Scrape") + vs := &ValidatorStats{} + err = json.NewDecoder(r).Decode(vs) + assert.NoError(t, err, "Unexpected error decoding result of validatorScraper.Scrape") + // CommonStats + assert.Equal(t, int64(6), vs.ValidatorTotal) + assert.Equal(t, int64(0), vs.ValidatorActive) } func mockNowFunc(fixedTime time.Time) func() time.Time { @@ -90,7 +118,7 @@ func TestValidatorAPIMessageDefaults(t *testing.T) { // 1+e6 ns per ms, so 123456789 ns rounded down should be 123 ms nowMillis := int64(1619811114123) vScraper := validatorScraper{} - vScraper.tripper = &mockRT{body: prometheusTestBody} + vScraper.tripper = &mockRT{body: statusFixtureOneOfEach + prometheusTestBody} r, err := vScraper.Scrape() assert.NoError(t, err, "unexpected error from validatorScraper.Scrape()") @@ -165,3 +193,32 @@ p2p_peer_count{state="Connecting"} 0 p2p_peer_count{state="Disconnected"} 62 p2p_peer_count{state="Disconnecting"} 0 ` + +var statusFixtureOneOfEach = `# HELP validator_statuses validator statuses: 0 UNKNOWN, 1 DEPOSITED, 2 PENDING, 3 ACTIVE, 4 EXITING, 5 SLASHING, 6 EXITED +# TYPE validator_statuses gauge +validator_statuses{pubkey="pk0"} 0 +validator_statuses{pubkey="pk1"} 1 +validator_statuses{pubkey="pk2"} 2 +validator_statuses{pubkey="pk3"} 3 +validator_statuses{pubkey="pk4"} 4 +validator_statuses{pubkey="pk5"} 5 +validator_statuses{pubkey="pk6"} 6 +` + +var statusFixtureAllActive = `# HELP validator_statuses validator statuses: 0 UNKNOWN, 1 DEPOSITED, 2 PENDING, 3 ACTIVE, 4 EXITING, 5 SLASHING, 6 EXITED +# TYPE validator_statuses gauge +validator_statuses{pubkey="pk0"} 3 +validator_statuses{pubkey="pk1"} 3 +validator_statuses{pubkey="pk2"} 3 +validator_statuses{pubkey="pk3"} 3 +` + +var statusFixtureNoneActive = `# HELP validator_statuses validator statuses: 0 UNKNOWN, 1 DEPOSITED, 2 PENDING, 3 ACTIVE, 4 EXITING, 5 SLASHING, 6 EXITED +# TYPE validator_statuses gauge +validator_statuses{pubkey="pk0"} 0 +validator_statuses{pubkey="pk1"} 1 +validator_statuses{pubkey="pk2"} 2 +validator_statuses{pubkey="pk3"} 4 +validator_statuses{pubkey="pk4"} 5 +validator_statuses{pubkey="pk5"} 6 +`