diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index 5c50933839..5e23615fdc 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -5885,6 +5885,7 @@ dependencies = [
"parking_lot 0.10.2",
"sc-block-builder",
"sc-client-api",
+ "sc-proposer-metrics",
"sc-telemetry",
"sc-transaction-pool",
"sp-api",
@@ -5894,6 +5895,7 @@ dependencies = [
"sp-inherents",
"sp-runtime",
"sp-transaction-pool",
+ "substrate-prometheus-endpoint",
"substrate-test-runtime-client",
"tokio-executor 0.2.0-alpha.6",
]
@@ -6601,6 +6603,14 @@ dependencies = [
"wasm-timer",
]
+[[package]]
+name = "sc-proposer-metrics"
+version = "0.8.0-dev"
+dependencies = [
+ "log",
+ "substrate-prometheus-endpoint",
+]
+
[[package]]
name = "sc-rpc"
version = "2.0.0-dev"
diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml
index d9ee8709d1..8fbe1cf0d8 100644
--- a/substrate/Cargo.toml
+++ b/substrate/Cargo.toml
@@ -45,6 +45,7 @@ members = [
"client/network-gossip",
"client/offchain",
"client/peerset",
+ "client/proposer-metrics",
"client/rpc-servers",
"client/rpc",
"client/rpc-api",
diff --git a/substrate/bin/node-template/node/src/service.rs b/substrate/bin/node-template/node/src/service.rs
index d02e9ea95e..8e57a04137 100644
--- a/substrate/bin/node-template/node/src/service.rs
+++ b/substrate/bin/node-template/node/src/service.rs
@@ -106,8 +106,11 @@ pub fn new_full(config: Configuration) -> Result.
+
//! A consensus proposer for "basic" chains which use the primitive inherent-data.
// FIXME #1021 move this into sp-consensus
@@ -38,21 +39,31 @@ use futures::{executor, future, future::Either};
use sp_blockchain::{HeaderBackend, ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed};
use std::marker::PhantomData;
+use prometheus_endpoint::Registry as PrometheusRegistry;
+use sc_proposer_metrics::MetricsLink as PrometheusMetrics;
+
/// Proposer factory.
pub struct ProposerFactory {
/// The client instance.
client: Arc,
/// The transaction pool.
transaction_pool: Arc,
+ /// Prometheus Link,
+ metrics: PrometheusMetrics,
/// phantom member to pin the `Backend` type.
_phantom: PhantomData,
}
impl ProposerFactory {
- pub fn new(client: Arc, transaction_pool: Arc) -> Self {
+ pub fn new(
+ client: Arc,
+ transaction_pool: Arc,
+ prometheus: Option<&PrometheusRegistry>,
+ ) -> Self {
ProposerFactory {
client,
transaction_pool,
+ metrics: PrometheusMetrics::new(prometheus),
_phantom: PhantomData,
}
}
@@ -87,6 +98,7 @@ impl ProposerFactory
parent_number: *parent_header.number(),
transaction_pool: self.transaction_pool.clone(),
now,
+ metrics: self.metrics.clone(),
_phantom: PhantomData,
}),
};
@@ -131,6 +143,7 @@ struct ProposerInner {
parent_number: <::Header as HeaderT>::Number,
transaction_pool: Arc,
now: Box time::Instant + Send + Sync>,
+ metrics: PrometheusMetrics,
_phantom: PhantomData,
}
@@ -219,6 +232,7 @@ impl ProposerInner
}
// proceed with transactions
+ let block_timer = self.metrics.report(|metrics| metrics.block_constructed.start_timer());
let mut is_first = true;
let mut skipped = 0;
let mut unqueue_invalid = Vec::new();
@@ -289,6 +303,9 @@ impl ProposerInner
let (block, storage_changes, proof) = block_builder.build()?.into_inner();
+ drop(block_timer);
+ self.metrics.report(|metrics| metrics.number_of_transactions.set(block.extrinsics().len() as u64));
+
info!("🎁 Prepared block for proposing at {} [hash: {:?}; parent_hash: {}; extrinsics ({}): [{}]]",
block.header().number(),
::Hash::from(block.header().hash()),
@@ -379,7 +396,7 @@ mod tests {
))
);
- let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone());
+ let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone(), None);
let cell = Mutex::new((false, time::Instant::now()));
let mut proposer = proposer_factory.init_with_now(
@@ -420,7 +437,7 @@ mod tests {
).0
);
- let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone());
+ let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone(), None);
let cell = Mutex::new((false, time::Instant::now()));
let mut proposer = proposer_factory.init_with_now(
@@ -470,7 +487,7 @@ mod tests {
))
);
- let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone());
+ let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone(), None);
let mut proposer = proposer_factory.init_with_now(
&client.header(&block_id).unwrap().unwrap(),
@@ -536,7 +553,7 @@ mod tests {
])
).unwrap();
- let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone());
+ let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone(), None);
let mut propose_block = |
client: &TestClient,
number,
diff --git a/substrate/client/basic-authorship/src/lib.rs b/substrate/client/basic-authorship/src/lib.rs
index 7f88844d90..7c77dde6b0 100644
--- a/substrate/client/basic-authorship/src/lib.rs
+++ b/substrate/client/basic-authorship/src/lib.rs
@@ -29,7 +29,7 @@
//! # let client = Arc::new(substrate_test_runtime_client::new());
//! # let txpool = Arc::new(BasicPool::new(Default::default(), Arc::new(FullChainApi::new(client.clone())), None).0);
//! // The first step is to create a `ProposerFactory`.
-//! let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone());
+//! let mut proposer_factory = ProposerFactory::new(client.clone(), txpool.clone(), None);
//!
//! // From this factory, we create a `Proposer`.
//! let proposer = proposer_factory.init(
diff --git a/substrate/client/consensus/manual-seal/src/lib.rs b/substrate/client/consensus/manual-seal/src/lib.rs
index 754203f7ba..de9711b2a8 100644
--- a/substrate/client/consensus/manual-seal/src/lib.rs
+++ b/substrate/client/consensus/manual-seal/src/lib.rs
@@ -225,7 +225,8 @@ mod tests {
let pool = Arc::new(BasicPool::new(Options::default(), api(), None).0);
let env = ProposerFactory::new(
client.clone(),
- pool.clone()
+ pool.clone(),
+ None,
);
// this test checks that blocks are created as soon as transactions are imported into the pool.
let (sender, receiver) = futures::channel::oneshot::channel();
@@ -289,7 +290,8 @@ mod tests {
let pool = Arc::new(BasicPool::new(Options::default(), api(), None).0);
let env = ProposerFactory::new(
client.clone(),
- pool.clone()
+ pool.clone(),
+ None,
);
// this test checks that blocks are created as soon as an engine command is sent over the stream.
let (mut sink, stream) = futures::channel::mpsc::channel(1024);
@@ -358,6 +360,7 @@ mod tests {
let env = ProposerFactory::new(
client.clone(),
pool.clone(),
+ None,
);
// this test checks that blocks are created as soon as an engine command is sent over the stream.
let (mut sink, stream) = futures::channel::mpsc::channel(1024);
diff --git a/substrate/client/proposer-metrics/Cargo.toml b/substrate/client/proposer-metrics/Cargo.toml
new file mode 100644
index 0000000000..9d510027ec
--- /dev/null
+++ b/substrate/client/proposer-metrics/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "sc-proposer-metrics"
+version = "0.8.0-dev"
+authors = ["Parity Technologies "]
+edition = "2018"
+license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
+homepage = "https://substrate.dev"
+repository = "https://github.com/paritytech/substrate/"
+description = "Basic metrics for block production."
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[dependencies]
+log = "0.4.8"
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.8.0-dev"}
diff --git a/substrate/client/proposer-metrics/src/lib.rs b/substrate/client/proposer-metrics/src/lib.rs
new file mode 100644
index 0000000000..5cb749f4a2
--- /dev/null
+++ b/substrate/client/proposer-metrics/src/lib.rs
@@ -0,0 +1,67 @@
+// 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 .
+
+//! Prometheus basic proposer metrics.
+
+use prometheus_endpoint::{register, PrometheusError, Registry, Histogram, HistogramOpts, Gauge, U64};
+
+/// Optional shareable link to basic authorship metrics.
+#[derive(Clone, Default)]
+pub struct MetricsLink(Option);
+
+impl MetricsLink {
+ pub fn new(registry: Option<&Registry>) -> Self {
+ Self(
+ registry.and_then(|registry|
+ Metrics::register(registry)
+ .map_err(|err| log::warn!("Failed to register proposer prometheus metrics: {}", err))
+ .ok()
+ )
+ )
+ }
+
+ pub fn report(&self, do_this: impl FnOnce(&Metrics) -> O) -> Option {
+ Some(do_this(self.0.as_ref()?))
+ }
+}
+
+/// Authorship metrics.
+#[derive(Clone)]
+pub struct Metrics {
+ pub block_constructed: Histogram,
+ pub number_of_transactions: Gauge,
+}
+
+impl Metrics {
+ pub fn register(registry: &Registry) -> Result {
+ Ok(Self {
+ block_constructed: register(
+ Histogram::with_opts(HistogramOpts::new(
+ "proposer_block_constructed",
+ "Histogram of time taken to construct new block",
+ ))?,
+ registry,
+ )?,
+ number_of_transactions: register(
+ Gauge::new(
+ "proposer_number_of_transactions",
+ "Number of transactions included in block",
+ )?,
+ registry,
+ )?,
+ })
+ }
+}
diff --git a/substrate/primitives/consensus/common/src/lib.rs b/substrate/primitives/consensus/common/src/lib.rs
index 52b034ffdd..fc56b22516 100644
--- a/substrate/primitives/consensus/common/src/lib.rs
+++ b/substrate/primitives/consensus/common/src/lib.rs
@@ -72,7 +72,9 @@ pub enum BlockStatus {
Unknown,
}
-/// Environment producer for a Consensus instance. Creates proposer instance and communication streams.
+/// Environment for a Consensus instance.
+///
+/// Creates proposer instance.
pub trait Environment {
/// The proposer type this creates.
type Proposer: Proposer + Send + 'static;