snarkos_node_metrics/
lib.rs1pub mod names;
17
18pub use names::*;
20
21pub use snarkvm::metrics::*;
23
24#[cfg(not(feature = "serial"))]
25use rayon::prelude::*;
26
27#[cfg(feature = "locktick")]
28use locktick::parking_lot::Mutex;
29#[cfg(not(feature = "locktick"))]
30use parking_lot::Mutex;
31use snarkvm::{
32 ledger::narwhal::TransmissionID,
33 prelude::{Block, Network, cfg_iter},
34};
35use std::{
36 collections::HashMap,
37 net::SocketAddr,
38 sync::{
39 Arc,
40 atomic::{AtomicUsize, Ordering},
41 },
42};
43use time::OffsetDateTime;
44
45pub fn initialize_metrics(ip: Option<SocketAddr>) {
47 let builder = metrics_exporter_prometheus::PrometheusBuilder::new();
49 if let Some(ip) = ip { builder.with_http_listener(ip) } else { builder }
50 .install()
51 .expect("can't build the prometheus exporter");
52
53 snarkvm::metrics::register_metrics();
55
56 for name in crate::names::GAUGE_NAMES {
58 register_gauge(name);
59 }
60 for name in crate::names::COUNTER_NAMES {
61 register_counter(name);
62 }
63 for name in crate::names::HISTOGRAM_NAMES {
64 register_histogram(name);
65 }
66
67 set_build_info();
69}
70
71pub fn update_block_metrics<N: Network>(block: &Block<N>) {
72 use snarkvm::ledger::ConfirmedTransaction;
73
74 let accepted_deploy = AtomicUsize::new(0);
75 let accepted_execute = AtomicUsize::new(0);
76 let rejected_deploy = AtomicUsize::new(0);
77 let rejected_execute = AtomicUsize::new(0);
78
79 cfg_iter!(block.transactions()).for_each(|tx| match tx {
81 ConfirmedTransaction::AcceptedDeploy(_, _, _) => {
82 accepted_deploy.fetch_add(1, Ordering::Relaxed);
83 }
84 ConfirmedTransaction::AcceptedExecute(_, _, _) => {
85 accepted_execute.fetch_add(1, Ordering::Relaxed);
86 }
87 ConfirmedTransaction::RejectedDeploy(_, _, _, _) => {
88 rejected_deploy.fetch_add(1, Ordering::Relaxed);
89 }
90 ConfirmedTransaction::RejectedExecute(_, _, _, _) => {
91 rejected_execute.fetch_add(1, Ordering::Relaxed);
92 }
93 });
94
95 increment_gauge(blocks::ACCEPTED_DEPLOY, accepted_deploy.load(Ordering::Relaxed) as f64);
96 increment_gauge(blocks::ACCEPTED_EXECUTE, accepted_execute.load(Ordering::Relaxed) as f64);
97 increment_gauge(blocks::REJECTED_DEPLOY, rejected_deploy.load(Ordering::Relaxed) as f64);
98 increment_gauge(blocks::REJECTED_EXECUTE, rejected_execute.load(Ordering::Relaxed) as f64);
99
100 increment_gauge(blocks::ABORTED_TRANSACTIONS, block.aborted_transaction_ids().len() as f64);
102 increment_gauge(blocks::ABORTED_SOLUTIONS, block.aborted_solution_ids().len() as f64);
103}
104
105pub fn add_transmission_latency_metric<N: Network>(
106 transmissions_tracker: &Arc<Mutex<HashMap<TransmissionID<N>, i64>>>,
107 block: &Block<N>,
108) {
109 const AGE_THRESHOLD_SECONDS: i32 = 30 * 60; let solution_ids: std::collections::HashSet<_> =
114 block.solutions().solution_ids().chain(block.aborted_solution_ids()).collect();
115
116 let transaction_ids: std::collections::HashSet<_> =
118 block.transaction_ids().chain(block.aborted_transaction_ids()).collect();
119
120 let mut transmissions_tracker = transmissions_tracker.lock();
121 let ts_now = OffsetDateTime::now_utc().unix_timestamp();
122
123 let keys_to_remove = cfg_iter!(&*transmissions_tracker)
125 .flat_map(|(transmission_id, timestamp)| {
126 let elapsed_time = std::time::Duration::from_secs((ts_now - *timestamp) as u64);
127
128 if elapsed_time.as_secs() > AGE_THRESHOLD_SECONDS as u64 {
129 match transmission_id {
131 TransmissionID::Solution(..) => increment_counter(consensus::STALE_UNCONFIRMED_SOLUTIONS),
132 TransmissionID::Transaction(..) => increment_counter(consensus::STALE_UNCONFIRMED_TRANSACTIONS),
133 TransmissionID::Ratification => {}
134 }
135 Some(*transmission_id)
136 } else {
137 let transmission_type = match transmission_id {
138 TransmissionID::Solution(solution_id, _) if solution_ids.contains(solution_id) => Some("solution"),
139 TransmissionID::Transaction(transaction_id, _) if transaction_ids.contains(transaction_id) => {
140 Some("transaction")
141 }
142 _ => None,
144 };
145
146 if let Some(transmission_type_string) = transmission_type {
147 histogram_label(
148 consensus::TRANSMISSION_LATENCY,
149 "transmission_type",
150 transmission_type_string.to_owned(),
151 elapsed_time.as_secs_f64(),
152 );
153 Some(*transmission_id)
154 } else {
155 None
156 }
157 }
158 })
159 .collect::<Vec<_>>();
160
161 for key in keys_to_remove {
163 transmissions_tracker.remove(&key);
164 }
165}
166
167mod built_info {
169 include!(concat!(env!("OUT_DIR"), "/built.rs"));
170}
171
172pub fn set_build_info() {
176 let version = built_info::PKG_VERSION;
177 let git_commit = built_info::GIT_COMMIT_HASH.unwrap_or("unknown");
178 let git_branch = built_info::GIT_HEAD_REF.unwrap_or("unknown");
179 let features = built_info::FEATURES_LOWERCASE_STR.replace(' ', "");
180
181 ::metrics::gauge!(build::BUILD_INFO, "version" => version.to_string()).set(1.0);
182 ::metrics::gauge!(build::BUILD_INFO, "git_commit" => git_commit.to_string()).set(1.0);
183 ::metrics::gauge!(build::BUILD_INFO, "git_branch" => git_branch.to_string()).set(1.0);
184 ::metrics::gauge!(build::BUILD_INFO, "features" => features).set(1.0);
185}