This repository has been archived by the owner on Nov 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Add runtime metrics provider Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Runner changes Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Some sample metrics in paras_inherent Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * update cargo toml Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fmt Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * bug Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * more fmt after merge Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Refactor metric prefix override Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fmt Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * remove bug comment Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Add runtime metric primitives Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Impl trace event parsing Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Update metrics Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * cargo lock Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fmt Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Fix target check Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Runtime metrics primitives Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Review feedback Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Runtime metrics crate Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Node side runtime metric changes Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * use runtime CounterVec instead of macro Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fmt nice Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * remove dead code Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * base58 decoding Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * base58 encoding Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fix warn Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * typo Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Review feedback Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Finish label support Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fmt Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * please compile Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * add feature gate Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fmt Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Comment cargo toml Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Fix cargo toml description Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Update doc. Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * switch to `runtime-metrics` feature Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fmt Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * cargo toml Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fix tests Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fixes Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * better ux Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * from_utf8_unchecked is safe Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fmt Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Add Counter and refactor Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Fixes Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * review fixes Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * more fixes Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * add integration test Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * dev deps Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * gitlab script update Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * review fixes Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * fix merge damage Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Run tests twice Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * small fix Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * typo Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * cargo lock Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * tests Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * spellcheck happy ? Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * more fixes Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * Guard tracing init Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * missing copyright Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> * update lockfile for substrate Co-authored-by: parity-processbot <>
- Loading branch information
Showing
23 changed files
with
1,015 additions
and
185 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
// Copyright 2021 Parity Technologies (UK) Ltd. | ||
// This file is part of Polkadot. | ||
|
||
// Polkadot 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. | ||
|
||
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
//! Runtime Metrics helpers. | ||
//! | ||
//! A runtime metric provider implementation that builds on top of Substrate wasm | ||
//! tracing support. This requires that the custom profiler (`TraceHandler`) to be | ||
//! registered in substrate via a `logger_hook()`. Events emitted from runtime are | ||
//! then captured/processed by the `TraceHandler` implementation. | ||
#![cfg(feature = "runtime-metrics")] | ||
|
||
use codec::Decode; | ||
use primitives::v1::{ | ||
RuntimeMetricLabelValues, RuntimeMetricOp, RuntimeMetricRegisterParams, RuntimeMetricUpdate, | ||
}; | ||
use std::{ | ||
collections::hash_map::HashMap, | ||
sync::{Arc, Mutex, MutexGuard}, | ||
}; | ||
use substrate_prometheus_endpoint::{ | ||
register, Counter, CounterVec, Opts, PrometheusError, Registry, U64, | ||
}; | ||
|
||
const LOG_TARGET: &'static str = "metrics::runtime"; | ||
const METRIC_PREFIX: &'static str = "polkadot"; | ||
|
||
/// Holds the registered Prometheus metric collections. | ||
#[derive(Clone, Default)] | ||
pub struct Metrics { | ||
counter_vecs: Arc<Mutex<HashMap<String, CounterVec<U64>>>>, | ||
counters: Arc<Mutex<HashMap<String, Counter<U64>>>>, | ||
} | ||
|
||
/// Runtime metrics wrapper. | ||
#[derive(Clone)] | ||
pub struct RuntimeMetricsProvider(Registry, Metrics); | ||
|
||
impl RuntimeMetricsProvider { | ||
/// Creates new instance. | ||
pub fn new(metrics_registry: Registry) -> Self { | ||
Self(metrics_registry, Metrics::default()) | ||
} | ||
|
||
/// Register a counter vec metric. | ||
pub fn register_countervec(&self, metric_name: &str, params: &RuntimeMetricRegisterParams) { | ||
self.with_counter_vecs_lock_held(|mut hashmap| { | ||
hashmap.entry(metric_name.to_owned()).or_insert(register( | ||
CounterVec::new( | ||
Opts::new(metric_name, params.description()), | ||
¶ms.labels().unwrap_or_default(), | ||
)?, | ||
&self.0, | ||
)?); | ||
Ok(()) | ||
}) | ||
} | ||
|
||
/// Register a counter metric. | ||
pub fn register_counter(&self, metric_name: &str, params: &RuntimeMetricRegisterParams) { | ||
self.with_counters_lock_held(|mut hashmap| { | ||
hashmap | ||
.entry(metric_name.to_owned()) | ||
.or_insert(register(Counter::new(metric_name, params.description())?, &self.0)?); | ||
return Ok(()) | ||
}) | ||
} | ||
|
||
/// Increment a counter with labels by a value. | ||
pub fn inc_counter_vec_by(&self, name: &str, value: u64, labels: &RuntimeMetricLabelValues) { | ||
self.with_counter_vecs_lock_held(|mut hashmap| { | ||
hashmap.entry(name.to_owned()).and_modify(|counter_vec| { | ||
counter_vec.with_label_values(&labels.as_str_vec()).inc_by(value) | ||
}); | ||
|
||
Ok(()) | ||
}); | ||
} | ||
|
||
/// Increment a counter by a value. | ||
pub fn inc_counter_by(&self, name: &str, value: u64) { | ||
self.with_counters_lock_held(|mut hashmap| { | ||
hashmap | ||
.entry(name.to_owned()) | ||
.and_modify(|counter_vec| counter_vec.inc_by(value)); | ||
Ok(()) | ||
}) | ||
} | ||
|
||
fn with_counters_lock_held<F>(&self, do_something: F) | ||
where | ||
F: FnOnce(MutexGuard<'_, HashMap<String, Counter<U64>>>) -> Result<(), PrometheusError>, | ||
{ | ||
let _ = self.1.counters.lock().map(do_something).or_else(|error| { | ||
tracing::error!( | ||
target: LOG_TARGET, | ||
"Cannot acquire the counter hashmap lock: {:?}", | ||
error | ||
); | ||
Err(error) | ||
}); | ||
} | ||
|
||
fn with_counter_vecs_lock_held<F>(&self, do_something: F) | ||
where | ||
F: FnOnce(MutexGuard<'_, HashMap<String, CounterVec<U64>>>) -> Result<(), PrometheusError>, | ||
{ | ||
let _ = self.1.counter_vecs.lock().map(do_something).or_else(|error| { | ||
tracing::error!( | ||
target: LOG_TARGET, | ||
"Cannot acquire the countervec hashmap lock: {:?}", | ||
error | ||
); | ||
Err(error) | ||
}); | ||
} | ||
} | ||
|
||
impl sc_tracing::TraceHandler for RuntimeMetricsProvider { | ||
fn handle_span(&self, _span: &sc_tracing::SpanDatum) {} | ||
fn handle_event(&self, event: &sc_tracing::TraceEvent) { | ||
if event | ||
.values | ||
.string_values | ||
.get("target") | ||
.unwrap_or(&String::default()) | ||
.ne("metrics") | ||
{ | ||
return | ||
} | ||
|
||
if let Some(update_op_bs58) = event.values.string_values.get("params") { | ||
// Deserialize the metric update struct. | ||
match RuntimeMetricUpdate::decode( | ||
&mut RuntimeMetricsProvider::parse_event_params(&update_op_bs58) | ||
.unwrap_or_default() | ||
.as_slice(), | ||
) { | ||
Ok(update_op) => { | ||
self.parse_metric_update(update_op); | ||
}, | ||
Err(e) => { | ||
tracing::error!(target: LOG_TARGET, "TraceEvent decode failed: {:?}", e); | ||
}, | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl RuntimeMetricsProvider { | ||
// Parse end execute the update operation. | ||
fn parse_metric_update(&self, update: RuntimeMetricUpdate) { | ||
let metric_name = &format!("{}_{}", METRIC_PREFIX, update.metric_name()); | ||
|
||
match update.op { | ||
RuntimeMetricOp::Register(ref params) => | ||
if params.labels.is_none() { | ||
self.register_counter(metric_name, ¶ms); | ||
} else { | ||
self.register_countervec(metric_name, ¶ms); | ||
}, | ||
RuntimeMetricOp::IncrementCounterVec(value, ref labels) => | ||
self.inc_counter_vec_by(metric_name, value, labels), | ||
RuntimeMetricOp::IncrementCounter(value) => self.inc_counter_by(metric_name, value), | ||
} | ||
} | ||
|
||
// Returns the `bs58` encoded metric update operation. | ||
fn parse_event_params(event_params: &str) -> Option<Vec<u8>> { | ||
// Shave " }" suffix. | ||
let new_len = event_params.len().saturating_sub(2); | ||
let event_params = &event_params[..new_len]; | ||
|
||
// Shave " { update_op: " prefix. | ||
const SKIP_CHARS: &'static str = " { update_op: "; | ||
if SKIP_CHARS.len() < event_params.len() { | ||
if SKIP_CHARS.eq_ignore_ascii_case(&event_params[..SKIP_CHARS.len()]) { | ||
return bs58::decode(&event_params[SKIP_CHARS.len()..].as_bytes()).into_vec().ok() | ||
} | ||
} | ||
|
||
// No event was parsed | ||
None | ||
} | ||
} | ||
|
||
/// Returns the custom profiling closure that we'll apply to the `LoggerBuilder`. | ||
pub fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration) -> () { | ||
|logger_builder, config| { | ||
if config.prometheus_registry().is_none() { | ||
tracing::debug!(target: LOG_TARGET, "Prometheus registry is not configured.",); | ||
return | ||
} | ||
let registry = config.prometheus_registry().cloned().unwrap(); | ||
let metrics_provider = RuntimeMetricsProvider::new(registry); | ||
logger_builder.with_custom_profiling(Box::new(metrics_provider)); | ||
} | ||
} |
Oops, something went wrong.