diff --git a/Cargo.lock b/Cargo.lock index d4dc8ac49b81d..4d6182176957a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6096,6 +6096,7 @@ dependencies = [ "sp-runtime", "sp-timestamp", "sp-version", + "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", ] @@ -6145,6 +6146,7 @@ dependencies = [ "sp-runtime", "sp-timestamp", "sp-version", + "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", ] @@ -6209,6 +6211,7 @@ dependencies = [ "sp-inherents", "sp-runtime", "sp-transaction-pool", + "substrate-prometheus-endpoint", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", "tempfile", @@ -6233,6 +6236,7 @@ dependencies = [ "sp-inherents", "sp-runtime", "sp-timestamp", + "substrate-prometheus-endpoint", ] [[package]] @@ -7403,6 +7407,7 @@ dependencies = [ "sp-test-primitives", "sp-utils", "sp-version", + "substrate-prometheus-endpoint", ] [[package]] diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 36555b5a223b5..d02e9ea95e494 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -43,7 +43,14 @@ macro_rules! new_full_start { let pool_api = sc_transaction_pool::FullChainApi::new(client.clone()); Ok(sc_transaction_pool::BasicPool::new(config, std::sync::Arc::new(pool_api), prometheus_registry)) })? - .with_import_queue(|_config, client, mut select_chain, _transaction_pool, spawn_task_handle| { + .with_import_queue(| + _config, + client, + mut select_chain, + _transaction_pool, + spawn_task_handle, + registry, + | { let select_chain = select_chain.take() .ok_or_else(|| sc_service::Error::SelectChainRequired)?; @@ -65,6 +72,7 @@ macro_rules! new_full_start { client, inherent_data_providers.clone(), spawn_task_handle, + registry, )?; import_setup = Some((grandpa_block_import, grandpa_link)); @@ -198,7 +206,16 @@ pub fn new_light(config: Configuration) -> Result Result( client: Arc, inherent_data_providers: InherentDataProviders, spawner: &S, + registry: Option<&Registry>, ) -> Result>, sp_consensus::Error> where B: BlockT, C::Api: BlockBuilderApi + AuraApi> + ApiExt, @@ -824,6 +826,7 @@ pub fn import_queue( justification_import, finality_proof_import, spawner, + registry, )) } diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index eed1d5d5da4cf..1a0c7b298586b 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -38,6 +38,7 @@ sc-consensus-uncles = { version = "0.8.0-dev", path = "../uncles" } sc-consensus-slots = { version = "0.8.0-dev", path = "../slots" } sp-runtime = { version = "2.0.0-dev", path = "../../../primitives/runtime" } fork-tree = { version = "2.0.0-dev", path = "../../../utils/fork-tree" } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.8.0-dev"} futures = "0.3.4" futures-timer = "3.0.1" parking_lot = "0.10.0" diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index d6498c119b361..553f4c9622dde 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -108,6 +108,7 @@ use sp_block_builder::BlockBuilder as BlockBuilderApi; use futures::prelude::*; use log::{debug, info, log, trace, warn}; +use prometheus_endpoint::Registry; use sc_consensus_slots::{ SlotWorker, SlotInfo, SlotCompatible, StorageChanges, CheckedHeader, check_equivocation, }; @@ -1272,6 +1273,7 @@ pub fn import_queue( client: Arc, inherent_data_providers: InherentDataProviders, spawner: &impl sp_core::traits::SpawnBlocking, + registry: Option<&Registry>, ) -> ClientResult>> where Inner: BlockImport> + Send + Sync + 'static, @@ -1295,6 +1297,7 @@ pub fn import_queue( justification_import, finality_proof_import, spawner, + registry, )) } diff --git a/client/consensus/manual-seal/Cargo.toml b/client/consensus/manual-seal/Cargo.toml index 5217b5b139067..3d42412f2ff4e 100644 --- a/client/consensus/manual-seal/Cargo.toml +++ b/client/consensus/manual-seal/Cargo.toml @@ -22,19 +22,20 @@ parking_lot = "0.10.0" serde = { version = "1.0", features=["derive"] } assert_matches = "1.3.0" -sc-client-api = { path = "../../../client/api" , version = "2.0.0-dev"} -sc-transaction-pool = { path = "../../transaction-pool" , version = "2.0.0-dev"} -sp-blockchain = { path = "../../../primitives/blockchain" , version = "2.0.0-dev"} -sp-consensus = { package = "sp-consensus", path = "../../../primitives/consensus/common" , version = "0.8.0-dev"} -sp-inherents = { path = "../../../primitives/inherents" , version = "2.0.0-dev"} -sp-runtime = { path = "../../../primitives/runtime" , version = "2.0.0-dev"} -sp-core = { path = "../../../primitives/core" , version = "2.0.0-dev"} -sp-transaction-pool = { path = "../../../primitives/transaction-pool" , version = "2.0.0-dev"} +sc-client-api = { path = "../../../client/api", version = "2.0.0-dev" } +sc-transaction-pool = { path = "../../transaction-pool", version = "2.0.0-dev" } +sp-blockchain = { path = "../../../primitives/blockchain", version = "2.0.0-dev" } +sp-consensus = { package = "sp-consensus", path = "../../../primitives/consensus/common", version = "0.8.0-dev" } +sp-inherents = { path = "../../../primitives/inherents", version = "2.0.0-dev" } +sp-runtime = { path = "../../../primitives/runtime", version = "2.0.0-dev" } +sp-core = { path = "../../../primitives/core", version = "2.0.0-dev" } +sp-transaction-pool = { path = "../../../primitives/transaction-pool", version = "2.0.0-dev" } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.8.0-dev" } [dev-dependencies] -sc-basic-authorship = { path = "../../basic-authorship" , version = "0.8.0-dev"} -substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" , version = "2.0.0-dev"} -substrate-test-runtime-transaction-pool = { path = "../../../test-utils/runtime/transaction-pool" , version = "2.0.0-dev"} +sc-basic-authorship = { path = "../../basic-authorship", version = "0.8.0-dev" } +substrate-test-runtime-client = { path = "../../../test-utils/runtime/client", version = "2.0.0-dev" } +substrate-test-runtime-transaction-pool = { path = "../../../test-utils/runtime/transaction-pool", version = "2.0.0-dev" } tokio = { version = "0.2", features = ["rt-core", "macros"] } env_logger = "0.7.0" tempfile = "3.1.0" diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index 14eaada56790e..6354e43ed3462 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -29,6 +29,7 @@ use sp_runtime::{traits::Block as BlockT, Justification}; use sc_client_api::backend::{Backend as ClientBackend, Finalizer}; use sc_transaction_pool::txpool; use std::{sync::Arc, marker::PhantomData}; +use prometheus_endpoint::Registry; mod error; mod finalize_block; @@ -69,6 +70,7 @@ impl Verifier for ManualSealVerifier { pub fn import_queue( block_import: BoxBlockImport, spawner: &impl sp_core::traits::SpawnBlocking, + registry: Option<&Registry>, ) -> BasicQueue where Block: BlockT, @@ -80,6 +82,7 @@ pub fn import_queue( None, None, spawner, + registry, ) } diff --git a/client/consensus/pow/Cargo.toml b/client/consensus/pow/Cargo.toml index cb4f44479eedd..3d47a983eaf76 100644 --- a/client/consensus/pow/Cargo.toml +++ b/client/consensus/pow/Cargo.toml @@ -26,3 +26,4 @@ log = "0.4.8" futures = { version = "0.3.1", features = ["compat"] } sp-timestamp = { version = "2.0.0-dev", path = "../../../primitives/timestamp" } derive_more = "0.99.2" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.8.0-dev"} diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index dc647448e0bf0..846377b7bce8f 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -54,6 +54,7 @@ use sp_consensus::import_queue::{ BoxBlockImport, BasicQueue, Verifier, BoxJustificationImport, BoxFinalityProofImport, }; use codec::{Encode, Decode}; +use prometheus_endpoint::Registry; use sc_client_api; use log::*; use sp_timestamp::{InherentError as TIError, TimestampInherentData}; @@ -465,6 +466,7 @@ pub fn import_queue( algorithm: Algorithm, inherent_data_providers: InherentDataProviders, spawner: &impl sp_core::traits::SpawnBlocking, + registry: Option<&Registry>, ) -> Result< PowImportQueue, sp_consensus::Error @@ -483,6 +485,7 @@ pub fn import_queue( justification_import, finality_proof_import, spawner, + registry, )) } diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 4347f80d2bee0..eada49d74161c 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -87,6 +87,7 @@ fn build_test_full_node(config: config::NetworkConfiguration) None, None, &sp_core::testing::SpawnBlockingExecutor::new(), + None, )); let worker = NetworkWorker::new(config::Params { diff --git a/client/network/test/src/block_import.rs b/client/network/test/src/block_import.rs index 6bc2b9dbadf2c..4e66ff879f120 100644 --- a/client/network/test/src/block_import.rs +++ b/client/network/test/src/block_import.rs @@ -93,6 +93,7 @@ fn async_import_queue_drops() { None, None, &executor, + None, ); drop(queue); } diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index cdcdf37ccf2a6..76bc2afa6953c 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -613,6 +613,7 @@ pub trait TestNetFactory: Sized { justification_import, finality_proof_import, &sp_core::testing::SpawnBlockingExecutor::new(), + None, )); let listen_addr = build_multiaddr![Memory(rand::random::())]; @@ -691,6 +692,7 @@ pub trait TestNetFactory: Sized { justification_import, finality_proof_import, &sp_core::testing::SpawnBlockingExecutor::new(), + None, )); let listen_addr = build_multiaddr![Memory(rand::random::())]; diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 413fe709f75dc..1bbf065825246 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -485,7 +485,7 @@ impl /// Defines which import queue to use. pub fn with_import_queue( self, - builder: impl FnOnce(&Configuration, Arc, Option, Arc, &SpawnTaskHandle) + builder: impl FnOnce(&Configuration, Arc, Option, Arc, &SpawnTaskHandle, Option<&Registry>) -> Result ) -> Result, Error> @@ -496,6 +496,7 @@ impl self.select_chain.clone(), self.transaction_pool.clone(), &self.task_manager.spawn_handle(), + self.config.prometheus_config.as_ref().map(|config| &config.registry), )?; Ok(ServiceBuilder { @@ -586,6 +587,7 @@ impl Option, Arc, &SpawnTaskHandle, + Option<&Registry>, ) -> Result<(UImpQu, Option), Error> ) -> Result, Error> @@ -598,6 +600,7 @@ impl self.select_chain.clone(), self.transaction_pool.clone(), &self.task_manager.spawn_handle(), + self.config.prometheus_config.as_ref().map(|config| &config.registry), )?; Ok(ServiceBuilder { @@ -630,12 +633,13 @@ impl Option, Arc, &SpawnTaskHandle, + Option<&Registry>, ) -> Result<(UImpQu, UFprb), Error> ) -> Result, Error> where TSc: Clone, TFchr: Clone { - self.with_import_queue_and_opt_fprb(|cfg, cl, b, f, sc, tx, tb| - builder(cfg, cl, b, f, sc, tx, tb) + self.with_import_queue_and_opt_fprb(|cfg, cl, b, f, sc, tx, tb, pr| + builder(cfg, cl, b, f, sc, tx, tb, pr) .map(|(q, f)| (q, Some(f))) ) } diff --git a/primitives/consensus/common/Cargo.toml b/primitives/consensus/common/Cargo.toml index 112505991360a..ec05e9fba187b 100644 --- a/primitives/consensus/common/Cargo.toml +++ b/primitives/consensus/common/Cargo.toml @@ -29,6 +29,7 @@ sp-utils = { version = "2.0.0-dev", path = "../../utils" } codec = { package = "parity-scale-codec", version = "1.3.0", features = ["derive"] } parking_lot = "0.10.0" serde = { version = "1.0", features = ["derive"] } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus", version = "0.8.0-dev"} [dev-dependencies] sp-test-primitives = { version = "2.0.0-dev", path = "../../test-primitives" } diff --git a/primitives/consensus/common/src/import_queue/basic_queue.rs b/primitives/consensus/common/src/import_queue/basic_queue.rs index 8b27dba4c39e7..c63c73bb42182 100644 --- a/primitives/consensus/common/src/import_queue/basic_queue.rs +++ b/primitives/consensus/common/src/import_queue/basic_queue.rs @@ -20,8 +20,10 @@ use futures::{prelude::*, task::Context, task::Poll}; use futures_timer::Delay; use sp_runtime::{Justification, traits::{Block as BlockT, Header as HeaderT, NumberFor}}; use sp_utils::mpsc::{TracingUnboundedSender, tracing_unbounded}; +use prometheus_endpoint::Registry; use crate::block_import::BlockOrigin; +use crate::metrics::Metrics; use crate::import_queue::{ BlockImportResult, BlockImportError, Verifier, BoxBlockImport, BoxFinalityProofImport, BoxJustificationImport, ImportQueue, Link, Origin, @@ -58,14 +60,21 @@ impl BasicQueue { justification_import: Option>, finality_proof_import: Option>, spawner: &impl sp_core::traits::SpawnBlocking, + prometheus_registry: Option<&Registry>, ) -> Self { let (result_sender, result_port) = buffered_link::buffered_link(); + let metrics = prometheus_registry.and_then(|r| + Metrics::register(r) + .map_err(|err| { log::warn!("Failed to register Prometheus metrics: {}", err); }) + .ok() + ); let (future, worker_sender) = BlockImportWorker::new( result_sender, verifier, block_import, justification_import, finality_proof_import, + metrics, ); spawner.spawn_blocking("basic-block-import-worker", future.boxed()); @@ -133,9 +142,15 @@ struct BlockImportWorker { justification_import: Option>, finality_proof_import: Option>, delay_between_blocks: Duration, + metrics: Option, _phantom: PhantomData, } +const METRIC_SUCCESS_FIELDS: [&'static str; 8] = [ + "success", "incomplete_header", "verification_failed", "bad_block", + "missing_state", "unknown_parent", "cancelled", "failed" +]; + impl BlockImportWorker { fn new>( result_sender: BufferedLinkSender, @@ -143,6 +158,7 @@ impl BlockImportWorker { block_import: BoxBlockImport, justification_import: Option>, finality_proof_import: Option>, + metrics: Option, ) -> (impl Future + Send, TracingUnboundedSender>) { let (sender, mut port) = tracing_unbounded("mpsc_block_import_worker"); @@ -151,6 +167,7 @@ impl BlockImportWorker { justification_import, finality_proof_import, delay_between_blocks: Duration::new(0, 0), + metrics, _phantom: PhantomData, }; @@ -241,9 +258,31 @@ impl BlockImportWorker { blocks: Vec> ) -> impl Future, V)> { let mut result_sender = self.result_sender.clone(); + let metrics = self.metrics.clone(); import_many_blocks(block_import, origin, blocks, verifier, self.delay_between_blocks) .then(move |(imported, count, results, block_import, verifier)| { + if let Some(metrics) = metrics { + let amounts = results.iter().fold([0u64; 8], |mut acc, result| { + match result.0 { + Ok(_) => acc[0] += 1, + Err(BlockImportError::IncompleteHeader(_)) => acc[1] += 1, + Err(BlockImportError::VerificationFailed(_,_)) => acc[2] += 1, + Err(BlockImportError::BadBlock(_)) => acc[3] += 1, + Err(BlockImportError::MissingState) => acc[4] += 1, + Err(BlockImportError::UnknownParent) => acc[5] += 1, + Err(BlockImportError::Cancelled) => acc[6] += 1, + Err(BlockImportError::Other(_)) => acc[7] += 1, + }; + acc + }); + for (idx, field) in METRIC_SUCCESS_FIELDS.iter().enumerate() { + let amount = amounts[idx]; + if amount > 0 { + metrics.import_queue_processed.with_label_values(&[&field]).inc_by(amount) + } + }; + } result_sender.blocks_processed(imported, count, results); future::ready((block_import, verifier)) }) diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index 9f338ad1d4e75..52b034ffdd667 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -44,6 +44,7 @@ pub mod block_import; mod select_chain; pub mod import_queue; pub mod evaluation; +mod metrics; // block size limit. const MAX_BLOCK_SIZE: usize = 4 * 1024 * 1024 + 512; diff --git a/primitives/consensus/common/src/metrics.rs b/primitives/consensus/common/src/metrics.rs new file mode 100644 index 0000000000000..90e01214d8d0b --- /dev/null +++ b/primitives/consensus/common/src/metrics.rs @@ -0,0 +1,39 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Metering tools for consensus + +use prometheus_endpoint::{register, U64, Registry, PrometheusError, Opts, CounterVec}; + +/// Generic Prometheus metrics for common consensus functionality. +#[derive(Clone)] +pub(crate) struct Metrics { + pub import_queue_processed: CounterVec, +} + +impl Metrics { + pub(crate) fn register(registry: &Registry) -> Result { + Ok(Self { + import_queue_processed: register( + CounterVec::new( + Opts::new("import_queue_processed_total", "Blocks processed by import queue"), + &["result"] // 'success or failure + )?, + registry, + )?, + }) + } +}