// This file is part of Substrate. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . //! BEEFY Prometheus metrics definition use crate::LOG_TARGET; use log::{debug, error}; use prometheus::{register, Counter, Gauge, PrometheusError, Registry, U64}; /// Helper trait for registering BEEFY metrics to Prometheus registry. pub(crate) trait PrometheusRegister: Sized { const DESCRIPTION: &'static str; fn register(registry: &Registry) -> Result; } /// BEEFY voting-related metrics exposed through Prometheus #[derive(Clone, Debug)] pub struct VoterMetrics { /// Current active validator set id pub beefy_validator_set_id: Gauge, /// Total number of votes sent by this node pub beefy_votes_sent: Counter, /// Best block finalized by BEEFY pub beefy_best_block: Gauge, /// Best block BEEFY voted on pub beefy_best_voted: Gauge, /// Next block BEEFY should vote on pub beefy_should_vote_on: Gauge, /// Number of sessions with lagging signed commitment on mandatory block pub beefy_lagging_sessions: Counter, /// Number of times no Authority public key found in store pub beefy_no_authority_found_in_store: Counter, /// Number of good votes successfully handled pub beefy_good_votes_processed: Counter, /// Number of equivocation votes received pub beefy_equivocation_votes: Counter, /// Number of invalid votes received pub beefy_invalid_votes: Counter, /// Number of valid but stale votes received pub beefy_stale_votes: Counter, /// Number of currently buffered justifications pub beefy_buffered_justifications: Gauge, /// Number of valid but stale justifications received pub beefy_stale_justifications: Counter, /// Number of valid justifications successfully imported pub beefy_imported_justifications: Counter, /// Number of justifications dropped due to full buffers pub beefy_buffered_justifications_dropped: Counter, } impl PrometheusRegister for VoterMetrics { const DESCRIPTION: &'static str = "voter"; fn register(registry: &Registry) -> Result { Ok(Self { beefy_validator_set_id: register( Gauge::new( "substrate_beefy_validator_set_id", "Current BEEFY active validator set id.", )?, registry, )?, beefy_votes_sent: register( Counter::new("substrate_beefy_votes_sent", "Number of votes sent by this node")?, registry, )?, beefy_best_block: register( Gauge::new("substrate_beefy_best_block", "Best block finalized by BEEFY")?, registry, )?, beefy_best_voted: register( Gauge::new("substrate_beefy_best_voted", "Best block voted on by BEEFY")?, registry, )?, beefy_should_vote_on: register( Gauge::new("substrate_beefy_should_vote_on", "Next block, BEEFY should vote on")?, registry, )?, beefy_lagging_sessions: register( Counter::new( "substrate_beefy_lagging_sessions", "Number of sessions with lagging signed commitment on mandatory block", )?, registry, )?, beefy_no_authority_found_in_store: register( Counter::new( "substrate_beefy_no_authority_found_in_store", "Number of times no Authority public key found in store", )?, registry, )?, beefy_good_votes_processed: register( Counter::new( "substrate_beefy_successful_handled_votes", "Number of good votes successfully handled", )?, registry, )?, beefy_equivocation_votes: register( Counter::new( "substrate_beefy_equivocation_votes", "Number of equivocation votes received", )?, registry, )?, beefy_invalid_votes: register( Counter::new("substrate_beefy_invalid_votes", "Number of invalid votes received")?, registry, )?, beefy_stale_votes: register( Counter::new( "substrate_beefy_stale_votes", "Number of valid but stale votes received", )?, registry, )?, beefy_buffered_justifications: register( Gauge::new( "substrate_beefy_buffered_justifications", "Number of currently buffered justifications", )?, registry, )?, beefy_stale_justifications: register( Counter::new( "substrate_beefy_stale_justifications", "Number of valid but stale justifications received", )?, registry, )?, beefy_imported_justifications: register( Counter::new( "substrate_beefy_imported_justifications", "Number of valid justifications successfully imported", )?, registry, )?, beefy_buffered_justifications_dropped: register( Counter::new( "substrate_beefy_buffered_justifications_dropped", "Number of justifications dropped due to full buffers", )?, registry, )?, }) } } /// BEEFY block-import-related metrics exposed through Prometheus #[derive(Clone, Debug)] pub struct BlockImportMetrics { /// Number of Good Justification imports pub beefy_good_justification_imports: Counter, /// Number of Bad Justification imports pub beefy_bad_justification_imports: Counter, } impl PrometheusRegister for BlockImportMetrics { const DESCRIPTION: &'static str = "block-import"; fn register(registry: &Registry) -> Result { Ok(Self { beefy_good_justification_imports: register( Counter::new( "substrate_beefy_good_justification_imports", "Number of good justifications on block-import", )?, registry, )?, beefy_bad_justification_imports: register( Counter::new( "substrate_beefy_bad_justification_imports", "Number of bad justifications on block-import", )?, registry, )?, }) } } /// BEEFY on-demand-justifications-related metrics exposed through Prometheus #[derive(Clone, Debug)] pub struct OnDemandIncomingRequestsMetrics { /// Number of Successful Justification responses pub beefy_successful_justification_responses: Counter, /// Number of Failed Justification responses pub beefy_failed_justification_responses: Counter, } impl PrometheusRegister for OnDemandIncomingRequestsMetrics { const DESCRIPTION: &'static str = "on-demand incoming justification requests"; fn register(registry: &Registry) -> Result { Ok(Self { beefy_successful_justification_responses: register( Counter::new( "substrate_beefy_successful_justification_responses", "Number of Successful Justification responses", )?, registry, )?, beefy_failed_justification_responses: register( Counter::new( "substrate_beefy_failed_justification_responses", "Number of Failed Justification responses", )?, registry, )?, }) } } /// BEEFY on-demand-justifications-related metrics exposed through Prometheus #[derive(Clone, Debug)] pub struct OnDemandOutgoingRequestsMetrics { /// Number of times there was no good peer to request justification from pub beefy_on_demand_justification_no_peer_to_request_from: Counter, /// Number of on-demand justification peer refused valid requests pub beefy_on_demand_justification_peer_refused: Counter, /// Number of on-demand justification peer error pub beefy_on_demand_justification_peer_error: Counter, /// Number of on-demand justification invalid proof pub beefy_on_demand_justification_invalid_proof: Counter, /// Number of on-demand justification good proof pub beefy_on_demand_justification_good_proof: Counter, } impl PrometheusRegister for OnDemandOutgoingRequestsMetrics { const DESCRIPTION: &'static str = "on-demand outgoing justification requests"; fn register(registry: &Registry) -> Result { Ok(Self { beefy_on_demand_justification_no_peer_to_request_from: register( Counter::new( "substrate_beefy_on_demand_justification_no_peer_to_request_from", "Number of times there was no good peer to request justification from", )?, registry, )?, beefy_on_demand_justification_peer_refused: register( Counter::new( "beefy_on_demand_justification_peer_refused", "Number of on-demand justification peer refused valid requests", )?, registry, )?, beefy_on_demand_justification_peer_error: register( Counter::new( "substrate_beefy_on_demand_justification_peer_error", "Number of on-demand justification peer error", )?, registry, )?, beefy_on_demand_justification_invalid_proof: register( Counter::new( "substrate_beefy_on_demand_justification_invalid_proof", "Number of on-demand justification invalid proof", )?, registry, )?, beefy_on_demand_justification_good_proof: register( Counter::new( "substrate_beefy_on_demand_justification_good_proof", "Number of on-demand justification good proof", )?, registry, )?, }) } } pub(crate) fn register_metrics( prometheus_registry: Option, ) -> Option { prometheus_registry.as_ref().map(T::register).and_then(|result| match result { Ok(metrics) => { debug!(target: LOG_TARGET, "🥩 Registered {} metrics", T::DESCRIPTION); Some(metrics) }, Err(err) => { error!( target: LOG_TARGET, "🥩 Failed to register {} metrics: {:?}", T::DESCRIPTION, err ); None }, }) } // Note: we use the `format` macro to convert an expr into a `u64`. This will fail, // if expr does not derive `Display`. #[macro_export] macro_rules! metric_set { ($self:ident, $m:ident, $v:expr) => {{ let val: u64 = format!("{}", $v).parse().unwrap(); if let Some(metrics) = $self.metrics.as_ref() { metrics.$m.set(val); } }}; } #[macro_export] macro_rules! metric_inc { ($self:ident, $m:ident) => {{ if let Some(metrics) = $self.metrics.as_ref() { metrics.$m.inc(); } }}; } #[macro_export] macro_rules! metric_get { ($self:ident, $m:ident) => {{ $self.metrics.as_ref().map(|metrics| metrics.$m.clone()) }}; } #[cfg(test)] pub(crate) mod tests { use super::*; #[test] fn should_register_metrics() { let registry = Some(Registry::new()); assert!(register_metrics::(registry.clone()).is_some()); assert!(register_metrics::(registry.clone()).is_some()); assert!(register_metrics::(registry.clone()).is_some()); assert!(register_metrics::(registry.clone()).is_some()); } }