pub mod names;
pub use names::*;
pub use snarkvm::metrics::*;
#[cfg(not(feature = "serial"))]
use rayon::prelude::*;
#[cfg(feature = "locktick")]
use locktick::parking_lot::Mutex;
#[cfg(not(feature = "locktick"))]
use parking_lot::Mutex;
use snarkvm::{
ledger::narwhal::TransmissionID,
prelude::{Block, Network, cfg_iter},
};
use std::{
collections::HashMap,
net::SocketAddr,
sync::{
Arc,
atomic::{AtomicUsize, Ordering},
},
};
use time::OffsetDateTime;
pub fn initialize_metrics(ip: Option<SocketAddr>) {
let builder = metrics_exporter_prometheus::PrometheusBuilder::new();
if let Some(ip) = ip { builder.with_http_listener(ip) } else { builder }
.install()
.expect("can't build the prometheus exporter");
snarkvm::metrics::register_metrics();
for name in crate::names::GAUGE_NAMES {
register_gauge(name);
}
for name in crate::names::COUNTER_NAMES {
register_counter(name);
}
for name in crate::names::HISTOGRAM_NAMES {
register_histogram(name);
}
set_build_info();
}
pub fn update_block_metrics<N: Network>(block: &Block<N>) {
use snarkvm::ledger::ConfirmedTransaction;
let accepted_deploy = AtomicUsize::new(0);
let accepted_execute = AtomicUsize::new(0);
let rejected_deploy = AtomicUsize::new(0);
let rejected_execute = AtomicUsize::new(0);
cfg_iter!(block.transactions()).for_each(|tx| match tx {
ConfirmedTransaction::AcceptedDeploy(_, _, _) => {
accepted_deploy.fetch_add(1, Ordering::Relaxed);
}
ConfirmedTransaction::AcceptedExecute(_, _, _) => {
accepted_execute.fetch_add(1, Ordering::Relaxed);
}
ConfirmedTransaction::RejectedDeploy(_, _, _, _) => {
rejected_deploy.fetch_add(1, Ordering::Relaxed);
}
ConfirmedTransaction::RejectedExecute(_, _, _, _) => {
rejected_execute.fetch_add(1, Ordering::Relaxed);
}
});
increment_gauge(blocks::ACCEPTED_DEPLOY, accepted_deploy.load(Ordering::Relaxed) as f64);
increment_gauge(blocks::ACCEPTED_EXECUTE, accepted_execute.load(Ordering::Relaxed) as f64);
increment_gauge(blocks::REJECTED_DEPLOY, rejected_deploy.load(Ordering::Relaxed) as f64);
increment_gauge(blocks::REJECTED_EXECUTE, rejected_execute.load(Ordering::Relaxed) as f64);
increment_gauge(blocks::ABORTED_TRANSACTIONS, block.aborted_transaction_ids().len() as f64);
increment_gauge(blocks::ABORTED_SOLUTIONS, block.aborted_solution_ids().len() as f64);
}
pub fn add_transmission_latency_metric<N: Network>(
transmissions_tracker: &Arc<Mutex<HashMap<TransmissionID<N>, i64>>>,
block: &Block<N>,
) {
const AGE_THRESHOLD_SECONDS: i32 = 30 * 60;
let solution_ids: std::collections::HashSet<_> =
block.solutions().solution_ids().chain(block.aborted_solution_ids()).collect();
let transaction_ids: std::collections::HashSet<_> =
block.transaction_ids().chain(block.aborted_transaction_ids()).collect();
let mut transmissions_tracker = transmissions_tracker.lock();
let ts_now = OffsetDateTime::now_utc().unix_timestamp();
let keys_to_remove = cfg_iter!(&*transmissions_tracker)
.flat_map(|(transmission_id, timestamp)| {
let elapsed_time = std::time::Duration::from_secs((ts_now - *timestamp) as u64);
if elapsed_time.as_secs() > AGE_THRESHOLD_SECONDS as u64 {
match transmission_id {
TransmissionID::Solution(..) => increment_counter(consensus::STALE_UNCONFIRMED_SOLUTIONS),
TransmissionID::Transaction(..) => increment_counter(consensus::STALE_UNCONFIRMED_TRANSACTIONS),
TransmissionID::Ratification => {}
}
Some(*transmission_id)
} else {
let transmission_type = match transmission_id {
TransmissionID::Solution(solution_id, _) if solution_ids.contains(solution_id) => Some("solution"),
TransmissionID::Transaction(transaction_id, _) if transaction_ids.contains(transaction_id) => {
Some("transaction")
}
_ => None,
};
if let Some(transmission_type_string) = transmission_type {
histogram_label(
consensus::TRANSMISSION_LATENCY,
"transmission_type",
transmission_type_string.to_owned(),
elapsed_time.as_secs_f64(),
);
Some(*transmission_id)
} else {
None
}
}
})
.collect::<Vec<_>>();
for key in keys_to_remove {
transmissions_tracker.remove(&key);
}
}
mod built_info {
include!(concat!(env!("OUT_DIR"), "/built.rs"));
}
pub fn set_build_info() {
let version = built_info::PKG_VERSION;
let git_commit = built_info::GIT_COMMIT_HASH.unwrap_or("unknown");
let git_branch = built_info::GIT_HEAD_REF.unwrap_or("unknown");
let features = built_info::FEATURES_LOWERCASE_STR.replace(' ', "");
::metrics::gauge!(build::BUILD_INFO, "version" => version.to_string()).set(1.0);
::metrics::gauge!(build::BUILD_INFO, "git_commit" => git_commit.to_string()).set(1.0);
::metrics::gauge!(build::BUILD_INFO, "git_branch" => git_branch.to_string()).set(1.0);
::metrics::gauge!(build::BUILD_INFO, "features" => features).set(1.0);
}