referrerpolicy=no-referrer-when-downgrade

polkadot_node_core_provisioner/
metrics.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17use crate::disputes::prioritized_selection::PartitionedDisputes;
18use polkadot_node_subsystem_util::metrics::{self, prometheus};
19
20#[derive(Clone)]
21struct MetricsInner {
22	/// Tracks successful/unsuccessful inherent data requests
23	inherent_data_requests: prometheus::CounterVec<prometheus::U64>,
24	/// How much time the `RequestInherentData` processing takes
25	request_inherent_data_duration: prometheus::Histogram,
26	/// How much time `ProvisionableData` processing takes
27	provisionable_data_duration: prometheus::Histogram,
28	/// Bitfields array length in `ProvisionerInherentData` (the result for `RequestInherentData`)
29	inherent_data_response_bitfields: prometheus::Histogram,
30
31	/// The following metrics track how many disputes/votes the runtime will have to process. These
32	/// will count all recent statements meaning every dispute from last sessions: 10 min on
33	/// Rococo, 60 min on Kusama and 4 hours on Polkadot. The metrics are updated only when the
34	/// node authors a block, so values vary across nodes.
35	inherent_data_dispute_statement_sets: prometheus::Counter<prometheus::U64>,
36	inherent_data_dispute_statements: prometheus::CounterVec<prometheus::U64>,
37
38	/// The disputes received from `disputes-coordinator` by partition
39	partitioned_disputes: prometheus::CounterVec<prometheus::U64>,
40
41	/// The disputes fetched from the runtime.
42	fetched_onchain_disputes: prometheus::Counter<prometheus::U64>,
43
44	/// The difference between the number of backed candidates in a block and the number of
45	/// backable candidates on the node side.
46	backable_vs_in_block: prometheus::Histogram,
47}
48
49/// Provisioner metrics.
50#[derive(Default, Clone)]
51pub struct Metrics(Option<MetricsInner>);
52
53impl Metrics {
54	/// Creates new dummy `Metrics` instance. Used for testing only.
55	#[cfg(test)]
56	pub fn new_dummy() -> Metrics {
57		Metrics(None)
58	}
59
60	pub(crate) fn on_inherent_data_request(&self, response: Result<(), ()>) {
61		if let Some(metrics) = &self.0 {
62			match response {
63				Ok(()) => metrics.inherent_data_requests.with_label_values(&["succeeded"]).inc(),
64				Err(()) => metrics.inherent_data_requests.with_label_values(&["failed"]).inc(),
65			}
66		}
67	}
68
69	/// Provide a timer for `request_inherent_data` which observes on drop.
70	pub(crate) fn time_request_inherent_data(
71		&self,
72	) -> Option<metrics::prometheus::prometheus::HistogramTimer> {
73		self.0
74			.as_ref()
75			.map(|metrics| metrics.request_inherent_data_duration.start_timer())
76	}
77
78	/// Provide a timer for `provisionable_data` which observes on drop.
79	pub(crate) fn time_provisionable_data(
80		&self,
81	) -> Option<metrics::prometheus::prometheus::HistogramTimer> {
82		self.0.as_ref().map(|metrics| metrics.provisionable_data_duration.start_timer())
83	}
84
85	pub(crate) fn observe_inherent_data_bitfields_count(&self, bitfields_count: usize) {
86		self.0.as_ref().map(|metrics| {
87			metrics.inherent_data_response_bitfields.observe(bitfields_count as f64)
88		});
89	}
90
91	pub(crate) fn inc_valid_statements_by(&self, votes: usize) {
92		if let Some(metrics) = &self.0 {
93			metrics
94				.inherent_data_dispute_statements
95				.with_label_values(&["valid"])
96				.inc_by(votes.try_into().unwrap_or(0));
97		}
98	}
99
100	pub(crate) fn inc_invalid_statements_by(&self, votes: usize) {
101		if let Some(metrics) = &self.0 {
102			metrics
103				.inherent_data_dispute_statements
104				.with_label_values(&["invalid"])
105				.inc_by(votes.try_into().unwrap_or(0));
106		}
107	}
108
109	pub(crate) fn inc_dispute_statement_sets_by(&self, disputes: usize) {
110		if let Some(metrics) = &self.0 {
111			metrics
112				.inherent_data_dispute_statement_sets
113				.inc_by(disputes.try_into().unwrap_or(0));
114		}
115	}
116
117	pub(crate) fn on_partition_recent_disputes(&self, disputes: &PartitionedDisputes) {
118		if let Some(metrics) = &self.0 {
119			let PartitionedDisputes {
120				inactive_unknown_onchain,
121				inactive_unconcluded_onchain: inactive_unconcluded_known_onchain,
122				active_unknown_onchain,
123				active_unconcluded_onchain,
124				active_concluded_onchain,
125				inactive_concluded_onchain: inactive_concluded_known_onchain,
126			} = disputes;
127
128			metrics
129				.partitioned_disputes
130				.with_label_values(&["inactive_unknown_onchain"])
131				.inc_by(inactive_unknown_onchain.len().try_into().unwrap_or(0));
132			metrics
133				.partitioned_disputes
134				.with_label_values(&["inactive_unconcluded_known_onchain"])
135				.inc_by(inactive_unconcluded_known_onchain.len().try_into().unwrap_or(0));
136			metrics
137				.partitioned_disputes
138				.with_label_values(&["active_unknown_onchain"])
139				.inc_by(active_unknown_onchain.len().try_into().unwrap_or(0));
140			metrics
141				.partitioned_disputes
142				.with_label_values(&["active_unconcluded_onchain"])
143				.inc_by(active_unconcluded_onchain.len().try_into().unwrap_or(0));
144			metrics
145				.partitioned_disputes
146				.with_label_values(&["active_concluded_onchain"])
147				.inc_by(active_concluded_onchain.len().try_into().unwrap_or(0));
148			metrics
149				.partitioned_disputes
150				.with_label_values(&["inactive_concluded_known_onchain"])
151				.inc_by(inactive_concluded_known_onchain.len().try_into().unwrap_or(0));
152		}
153	}
154
155	pub(crate) fn on_fetched_onchain_disputes(&self, onchain_count: u64) {
156		if let Some(metrics) = &self.0 {
157			metrics.fetched_onchain_disputes.inc_by(onchain_count);
158		}
159	}
160
161	pub(crate) fn observe_backable_vs_in_block(&self, diff: isize) {
162		self.0.as_ref().map(|metrics| metrics.backable_vs_in_block.observe(diff as f64));
163	}
164}
165
166impl metrics::Metrics for Metrics {
167	fn try_register(registry: &prometheus::Registry) -> Result<Self, prometheus::PrometheusError> {
168		let metrics = MetricsInner {
169			inherent_data_requests: prometheus::register(
170				prometheus::CounterVec::new(
171					prometheus::Opts::new(
172						"polkadot_parachain_inherent_data_requests_total",
173						"Number of InherentData requests served by provisioner.",
174					),
175					&["success"],
176				)?,
177				registry,
178			)?,
179			request_inherent_data_duration: prometheus::register(
180				prometheus::Histogram::with_opts(prometheus::HistogramOpts::new(
181					"polkadot_parachain_provisioner_request_inherent_data_time",
182					"Time spent within `provisioner::request_inherent_data`",
183				))?,
184				registry,
185			)?,
186			provisionable_data_duration: prometheus::register(
187				prometheus::Histogram::with_opts(prometheus::HistogramOpts::new(
188					"polkadot_parachain_provisioner_provisionable_data_time",
189					"Time spent within `provisioner::provisionable_data`",
190				))?,
191				registry,
192			)?,
193			inherent_data_dispute_statements: prometheus::register(
194				prometheus::CounterVec::new(
195					prometheus::Opts::new(
196						"polkadot_parachain_inherent_data_dispute_statements",
197						"Number of dispute statements passed to `create_inherent()`.",
198					),
199					&["validity"],
200				)?,
201				&registry,
202			)?,
203			inherent_data_dispute_statement_sets: prometheus::register(
204				prometheus::Counter::new(
205					"polkadot_parachain_inherent_data_dispute_statement_sets",
206					"Number of dispute statements sets passed to `create_inherent()`.",
207				)?,
208				registry,
209			)?,
210			inherent_data_response_bitfields: prometheus::register(
211				prometheus::Histogram::with_opts(
212					prometheus::HistogramOpts::new(
213						"polkadot_parachain_provisioner_inherent_data_response_bitfields_sent",
214						"Number of inherent bitfields sent in response to `ProvisionerMessage::RequestInherentData`.",
215					).buckets(vec![0.0, 25.0, 50.0, 100.0, 150.0, 200.0, 250.0, 300.0, 400.0, 500.0, 600.0]),
216				)?,
217				registry,
218			)?,
219			backable_vs_in_block: prometheus::register(
220				prometheus::Histogram::with_opts(
221					prometheus::HistogramOpts::new(
222						"polkadot_parachain_provisioner_backable_vs_in_block",
223						"Difference between number of backable blocks and number of backed candidates in block",
224					).buckets(vec![-100.0, -50.0, -40.0, -30.0, -20.0, -15.0, -10.0, -5.0, 0.0, 5.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0, 100.0]),
225				)?,
226				registry,
227			)?,
228			partitioned_disputes: prometheus::register(
229				prometheus::CounterVec::new(
230					prometheus::Opts::new(
231						"polkadot_parachain_provisioner_partitioned_disputes",
232						"Number of disputes partitioned by type.",
233					),
234					&["partition"],
235				)?,
236				&registry,
237			)?,
238			fetched_onchain_disputes: prometheus::register(
239				prometheus::Counter::new("polkadot_parachain_fetched_onchain_disputes", "Number of disputes fetched from the runtime"
240				)?,
241				&registry,
242			)?,
243		};
244		Ok(Metrics(Some(metrics)))
245	}
246}