From 0403c718d01bc4bc21b7905f53768a0fbd90c861 Mon Sep 17 00:00:00 2001 From: Andre da Silva Date: Fri, 28 Nov 2025 11:00:54 -0300 Subject: [PATCH] Several metrics changes --- linera-core/src/chain_worker/actor.rs | 30 ++++- linera-core/src/worker.rs | 27 ++++- linera-rpc/src/grpc/server.rs | 25 ++++- linera-storage/src/db_storage.rs | 2 +- linera-views-derive/src/lib.rs | 31 +++++- ...est_generate_root_view_code_metrics_C.snap | 9 ++ ...e_root_view_code_metrics_C_with_where.snap | 9 ++ ..._root_view_code_metrics_CustomContext.snap | 9 ++ ...code_metrics_CustomContext_with_where.snap | 9 ++ ...ode_metrics_custom__GenericContext_T_.snap | 9 ++ ..._custom__GenericContext_T__with_where.snap | 9 ++ ...metrics_custom__path__to__ContextType.snap | 9 ++ ...tom__path__to__ContextType_with_where.snap | 9 ++ linera-views/src/backends/metering.rs | 103 ++++++++++++------ linera-views/src/metrics.rs | 11 ++ 15 files changed, 256 insertions(+), 45 deletions(-) diff --git a/linera-core/src/chain_worker/actor.rs b/linera-core/src/chain_worker/actor.rs index ecb17f170506..d9d55003b52b 100644 --- a/linera-core/src/chain_worker/actor.rs +++ b/linera-core/src/chain_worker/actor.rs @@ -57,8 +57,10 @@ pub(crate) type ChainWorkerRequestReceiver = mod metrics { use std::sync::LazyLock; - use linera_base::prometheus_util::{exponential_bucket_interval, register_histogram}; - use prometheus::Histogram; + use linera_base::prometheus_util::{ + exponential_bucket_interval, register_histogram, register_int_gauge, + }; + use prometheus::{Histogram, IntGauge}; pub static CHAIN_WORKER_REQUEST_QUEUE_WAIT_TIME: LazyLock = LazyLock::new(|| { register_histogram( @@ -67,6 +69,22 @@ mod metrics { exponential_bucket_interval(0.1_f64, 10_000.0), ) }); + + /// Number of active chain worker actor tasks (outer loop of handle_requests). + pub static CHAIN_WORKER_ACTORS_ACTIVE: LazyLock = LazyLock::new(|| { + register_int_gauge( + "chain_worker_actors_active", + "Number of active chain worker actor tasks", + ) + }); + + /// Number of chain workers with chain state loaded in memory (inner loop of handle_requests). + pub static CHAIN_WORKER_STATES_LOADED: LazyLock = LazyLock::new(|| { + register_int_gauge( + "chain_worker_states_loaded", + "Number of chain workers with chain state loaded in memory", + ) + }); } /// A request for the [`ChainWorkerActor`]. @@ -327,6 +345,8 @@ where request_receiver: ChainWorkerRequestReceiver, is_tracked: bool, ) { + #[cfg(with_metrics)] + metrics::CHAIN_WORKER_ACTORS_ACTIVE.inc(); let actor = ChainWorkerActor { config, storage, @@ -343,6 +363,8 @@ where { tracing::error!("Chain actor error: {err}"); } + #[cfg(with_metrics)] + metrics::CHAIN_WORKER_ACTORS_ACTIVE.dec(); } /// Returns the TTL timeout timestamp. @@ -458,6 +480,8 @@ where ) .instrument(span.clone()) .await?; + #[cfg(with_metrics)] + metrics::CHAIN_WORKER_STATES_LOADED.inc(); Box::pin(worker.handle_request(request)) .instrument(span) @@ -488,6 +512,8 @@ where trace!("Unloading chain state of {} ...", self.chain_id); worker.clear_shared_chain_view().await; drop(worker); + #[cfg(with_metrics)] + metrics::CHAIN_WORKER_STATES_LOADED.dec(); if let Some(task) = service_runtime_task { task.await?; } diff --git a/linera-core/src/worker.rs b/linera-core/src/worker.rs index 21b6d427832e..fe66592cbd73 100644 --- a/linera-core/src/worker.rs +++ b/linera-core/src/worker.rs @@ -64,9 +64,9 @@ mod metrics { use linera_base::prometheus_util::{ exponential_bucket_interval, register_histogram_vec, register_int_counter, - register_int_counter_vec, + register_int_counter_vec, register_int_gauge, }; - use prometheus::{HistogramVec, IntCounter, IntCounterVec}; + use prometheus::{HistogramVec, IntCounter, IntCounterVec, IntGauge}; pub static NUM_ROUNDS_IN_CERTIFICATE: LazyLock = LazyLock::new(|| { register_histogram_vec( @@ -92,6 +92,9 @@ mod metrics { pub static INCOMING_BUNDLE_COUNT: LazyLock = LazyLock::new(|| register_int_counter("incoming_bundle_count", "Incoming bundle count")); + pub static INCOMING_MESSAGE_COUNT: LazyLock = + LazyLock::new(|| register_int_counter("incoming_message_count", "Incoming message count")); + pub static OPERATION_COUNT: LazyLock = LazyLock::new(|| register_int_counter("operation_count", "Operation count")); @@ -113,6 +116,14 @@ mod metrics { "Number of chain info queries processed", ) }); + + /// Number of cached chain worker channel endpoints in the BTreeMap. + pub static CHAIN_WORKER_ENDPOINTS_CACHED: LazyLock = LazyLock::new(|| { + register_int_gauge( + "chain_worker_endpoints_cached", + "Number of cached chain worker channel endpoints", + ) + }); } /// Instruct the networking layer to send cross-chain requests and/or push notifications. @@ -934,6 +945,8 @@ where // Put back the sender in the cache for next time. chain_workers.insert(chain_id, sender); + #[cfg(with_metrics)] + metrics::CHAIN_WORKER_ENDPOINTS_CACHED.set(chain_workers.len() as i64); Ok(new_channel) } @@ -1011,6 +1024,12 @@ where certificate.round.number(), certificate.block().body.transactions.len() as u64, certificate.block().body.incoming_bundles().count() as u64, + certificate + .block() + .body + .incoming_bundles() + .map(|b| b.messages().count()) + .sum::() as u64, certificate.block().body.operations().count() as u64, certificate .signatures() @@ -1032,6 +1051,7 @@ where round_number, confirmed_transactions, confirmed_incoming_bundles, + confirmed_incoming_messages, confirmed_operations, validators_with_signatures, ) = metrics_data; @@ -1046,6 +1066,9 @@ where if confirmed_incoming_bundles > 0 { metrics::INCOMING_BUNDLE_COUNT.inc_by(confirmed_incoming_bundles); } + if confirmed_incoming_messages > 0 { + metrics::INCOMING_MESSAGE_COUNT.inc_by(confirmed_incoming_messages); + } if confirmed_operations > 0 { metrics::OPERATION_COUNT.inc_by(confirmed_operations); } diff --git a/linera-rpc/src/grpc/server.rs b/linera-rpc/src/grpc/server.rs index 7f96428bffb0..6a75b42d2bb7 100644 --- a/linera-rpc/src/grpc/server.rs +++ b/linera-rpc/src/grpc/server.rs @@ -102,6 +102,22 @@ mod metrics { &[], ) }); + + pub static NOTIFICATIONS_SKIPPED_RECEIVER_LAG: LazyLock = LazyLock::new(|| { + register_int_counter_vec( + "notifications_skipped_receiver_lag", + "Number of notifications skipped because receiver lagged behind sender", + &[], + ) + }); + + pub static NOTIFICATIONS_DROPPED_NO_RECEIVER: LazyLock = LazyLock::new(|| { + register_int_counter_vec( + "notifications_dropped_no_receiver", + "Number of notifications dropped because no receiver was available", + &[], + ) + }); } #[derive(Clone)] @@ -320,6 +336,10 @@ where nickname, skipped_count, "notification receiver lagged, messages were skipped" ); + #[cfg(with_metrics)] + metrics::NOTIFICATIONS_SKIPPED_RECEIVER_LAG + .with_label_values(&[]) + .inc_by(skipped_count); continue; } Err(RecvError::Closed) => { @@ -395,7 +415,10 @@ where trace!("Scheduling notification query"); if let Err(error) = notification_sender.send(notification) { error!(%error, "dropping notification"); - break; + #[cfg(with_metrics)] + metrics::NOTIFICATIONS_DROPPED_NO_RECEIVER + .with_label_values(&[]) + .inc(); } } } diff --git a/linera-storage/src/db_storage.rs b/linera-storage/src/db_storage.rs index fc40938ef695..05c36d25f95a 100644 --- a/linera-storage/src/db_storage.rs +++ b/linera-storage/src/db_storage.rs @@ -182,7 +182,7 @@ pub mod metrics { "load_chain_latency", "The latency to load a chain state", &[], - exponential_bucket_latencies(10.0), + exponential_bucket_latencies(1000.0), ) }); diff --git a/linera-views-derive/src/lib.rs b/linera-views-derive/src/lib.rs index 0ec6a77459fb..ce49ba774949 100644 --- a/linera-views-derive/src/lib.rs +++ b/linera-views-derive/src/lib.rs @@ -246,7 +246,7 @@ fn generate_root_view_code(input: ItemStruct) -> TokenStream2 { } = Constraints::get(&input); let struct_name = &input.ident; - let increment_counter = if cfg!(feature = "metrics") { + let metrics_code = if cfg!(feature = "metrics") { quote! { #[cfg(not(target_arch = "wasm32"))] linera_views::metrics::increment_counter( @@ -259,6 +259,29 @@ fn generate_root_view_code(input: ItemStruct) -> TokenStream2 { quote! {} }; + let write_batch_with_metrics = if cfg!(feature = "metrics") { + quote! { + if !batch.is_empty() { + #[cfg(not(target_arch = "wasm32"))] + let start = std::time::Instant::now(); + self.context().store().write_batch(batch).await?; + #[cfg(not(target_arch = "wasm32"))] + { + let latency_ms = start.elapsed().as_secs_f64() * 1000.0; + linera_views::metrics::SAVE_VIEW_LATENCY + .with_label_values(&[stringify!(#struct_name)]) + .observe(latency_ms); + } + } + } + } else { + quote! { + if !batch.is_empty() { + self.context().store().write_batch(batch).await?; + } + } + }; + quote! { impl #impl_generics linera_views::views::RootView for #struct_name #type_generics where @@ -267,12 +290,10 @@ fn generate_root_view_code(input: ItemStruct) -> TokenStream2 { { async fn save(&mut self) -> Result<(), linera_views::ViewError> { use linera_views::{context::Context as _, batch::Batch, store::WritableKeyValueStore as _, views::View as _}; - #increment_counter + #metrics_code let mut batch = Batch::new(); self.pre_save(&mut batch)?; - if !batch.is_empty() { - self.context().store().write_batch(batch).await?; - } + #write_batch_with_metrics self.post_save(); Ok(()) } diff --git a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_C.snap b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_C.snap index 4ee531396b46..890fdfa1b1ba 100644 --- a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_C.snap +++ b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_C.snap @@ -20,7 +20,16 @@ where let mut batch = Batch::new(); self.pre_save(&mut batch)?; if !batch.is_empty() { + #[cfg(not(target_arch = "wasm32"))] + let start = std::time::Instant::now(); self.context().store().write_batch(batch).await?; + #[cfg(not(target_arch = "wasm32"))] + { + let latency_ms = start.elapsed().as_secs_f64() * 1000.0; + linera_views::metrics::SAVE_VIEW_LATENCY + .with_label_values(&[stringify!(TestView)]) + .observe(latency_ms); + } } self.post_save(); Ok(()) diff --git a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_C_with_where.snap b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_C_with_where.snap index 04b2bfca0bde..93dad18a0658 100644 --- a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_C_with_where.snap +++ b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_C_with_where.snap @@ -21,7 +21,16 @@ where let mut batch = Batch::new(); self.pre_save(&mut batch)?; if !batch.is_empty() { + #[cfg(not(target_arch = "wasm32"))] + let start = std::time::Instant::now(); self.context().store().write_batch(batch).await?; + #[cfg(not(target_arch = "wasm32"))] + { + let latency_ms = start.elapsed().as_secs_f64() * 1000.0; + linera_views::metrics::SAVE_VIEW_LATENCY + .with_label_values(&[stringify!(TestView)]) + .observe(latency_ms); + } } self.post_save(); Ok(()) diff --git a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_CustomContext.snap b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_CustomContext.snap index 102fd5a8eda7..56b24891e0b0 100644 --- a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_CustomContext.snap +++ b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_CustomContext.snap @@ -20,7 +20,16 @@ where let mut batch = Batch::new(); self.pre_save(&mut batch)?; if !batch.is_empty() { + #[cfg(not(target_arch = "wasm32"))] + let start = std::time::Instant::now(); self.context().store().write_batch(batch).await?; + #[cfg(not(target_arch = "wasm32"))] + { + let latency_ms = start.elapsed().as_secs_f64() * 1000.0; + linera_views::metrics::SAVE_VIEW_LATENCY + .with_label_values(&[stringify!(TestView)]) + .observe(latency_ms); + } } self.post_save(); Ok(()) diff --git a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_CustomContext_with_where.snap b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_CustomContext_with_where.snap index 22bf70dafdfd..a750e28e631b 100644 --- a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_CustomContext_with_where.snap +++ b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_CustomContext_with_where.snap @@ -21,7 +21,16 @@ where let mut batch = Batch::new(); self.pre_save(&mut batch)?; if !batch.is_empty() { + #[cfg(not(target_arch = "wasm32"))] + let start = std::time::Instant::now(); self.context().store().write_batch(batch).await?; + #[cfg(not(target_arch = "wasm32"))] + { + let latency_ms = start.elapsed().as_secs_f64() * 1000.0; + linera_views::metrics::SAVE_VIEW_LATENCY + .with_label_values(&[stringify!(TestView)]) + .observe(latency_ms); + } } self.post_save(); Ok(()) diff --git a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__GenericContext_T_.snap b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__GenericContext_T_.snap index 102fd5a8eda7..56b24891e0b0 100644 --- a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__GenericContext_T_.snap +++ b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__GenericContext_T_.snap @@ -20,7 +20,16 @@ where let mut batch = Batch::new(); self.pre_save(&mut batch)?; if !batch.is_empty() { + #[cfg(not(target_arch = "wasm32"))] + let start = std::time::Instant::now(); self.context().store().write_batch(batch).await?; + #[cfg(not(target_arch = "wasm32"))] + { + let latency_ms = start.elapsed().as_secs_f64() * 1000.0; + linera_views::metrics::SAVE_VIEW_LATENCY + .with_label_values(&[stringify!(TestView)]) + .observe(latency_ms); + } } self.post_save(); Ok(()) diff --git a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__GenericContext_T__with_where.snap b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__GenericContext_T__with_where.snap index 22bf70dafdfd..a750e28e631b 100644 --- a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__GenericContext_T__with_where.snap +++ b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__GenericContext_T__with_where.snap @@ -21,7 +21,16 @@ where let mut batch = Batch::new(); self.pre_save(&mut batch)?; if !batch.is_empty() { + #[cfg(not(target_arch = "wasm32"))] + let start = std::time::Instant::now(); self.context().store().write_batch(batch).await?; + #[cfg(not(target_arch = "wasm32"))] + { + let latency_ms = start.elapsed().as_secs_f64() * 1000.0; + linera_views::metrics::SAVE_VIEW_LATENCY + .with_label_values(&[stringify!(TestView)]) + .observe(latency_ms); + } } self.post_save(); Ok(()) diff --git a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__path__to__ContextType.snap b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__path__to__ContextType.snap index 102fd5a8eda7..56b24891e0b0 100644 --- a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__path__to__ContextType.snap +++ b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__path__to__ContextType.snap @@ -20,7 +20,16 @@ where let mut batch = Batch::new(); self.pre_save(&mut batch)?; if !batch.is_empty() { + #[cfg(not(target_arch = "wasm32"))] + let start = std::time::Instant::now(); self.context().store().write_batch(batch).await?; + #[cfg(not(target_arch = "wasm32"))] + { + let latency_ms = start.elapsed().as_secs_f64() * 1000.0; + linera_views::metrics::SAVE_VIEW_LATENCY + .with_label_values(&[stringify!(TestView)]) + .observe(latency_ms); + } } self.post_save(); Ok(()) diff --git a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__path__to__ContextType_with_where.snap b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__path__to__ContextType_with_where.snap index 22bf70dafdfd..a750e28e631b 100644 --- a/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__path__to__ContextType_with_where.snap +++ b/linera-views-derive/src/snapshots/linera_views_derive__tests__test_generate_root_view_code_metrics_custom__path__to__ContextType_with_where.snap @@ -21,7 +21,16 @@ where let mut batch = Batch::new(); self.pre_save(&mut batch)?; if !batch.is_empty() { + #[cfg(not(target_arch = "wasm32"))] + let start = std::time::Instant::now(); self.context().store().write_batch(batch).await?; + #[cfg(not(target_arch = "wasm32"))] + { + let latency_ms = start.elapsed().as_secs_f64() * 1000.0; + linera_views::metrics::SAVE_VIEW_LATENCY + .with_label_values(&[stringify!(TestView)]) + .observe(latency_ms); + } } self.post_save(); Ok(()) diff --git a/linera-views/src/backends/metering.rs b/linera-views/src/backends/metering.rs index 3af18988ccfa..476e0c539fe6 100644 --- a/linera-views/src/backends/metering.rs +++ b/linera-views/src/backends/metering.rs @@ -10,9 +10,10 @@ use std::{ use convert_case::{Case, Casing}; use linera_base::prometheus_util::{ - register_histogram_vec, register_int_counter_vec, MeasureLatency as _, + exponential_bucket_latencies, register_histogram_vec, register_int_counter_vec, + MeasureLatency as _, }; -use prometheus::{HistogramVec, IntCounterVec}; +use prometheus::{exponential_buckets, HistogramVec, IntCounterVec}; #[cfg(with_testing)] use crate::store::TestKeyValueDatabase; @@ -92,73 +93,97 @@ impl KeyValueStoreMetrics { let var_name = name.replace(' ', "_"); let title_name = name.to_case(Case::Snake); + // Latency buckets in milliseconds: up to 10 seconds + let latency_buckets = exponential_bucket_latencies(10000.0); + // Size buckets in bytes: 1B to 10MB + let size_buckets = + Some(exponential_buckets(1.0, 4.0, 12).expect("Size buckets creation should not fail")); + // Count buckets: 1 to 100,000 + let count_buckets = Some( + exponential_buckets(1.0, 3.0, 11).expect("Count buckets creation should not fail"), + ); + let entry1 = format!("{}_read_value_bytes_latency", var_name); let entry2 = format!("{} read value bytes latency", title_name); - let read_value_bytes_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let read_value_bytes_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_contains_key_latency", var_name); let entry2 = format!("{} contains key latency", title_name); - let contains_key_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let contains_key_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_contains_keys_latency", var_name); let entry2 = format!("{} contains keys latency", title_name); - let contains_keys_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let contains_keys_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_read_multi_value_bytes_latency", var_name); let entry2 = format!("{} read multi value bytes latency", title_name); - let read_multi_values_bytes_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let read_multi_values_bytes_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_find_keys_by_prefix_latency", var_name); let entry2 = format!("{} find keys by prefix latency", title_name); - let find_keys_by_prefix_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let find_keys_by_prefix_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_find_key_values_by_prefix_latency", var_name); let entry2 = format!("{} find key values by prefix latency", title_name); - let find_key_values_by_prefix_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let find_key_values_by_prefix_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_write_batch_latency", var_name); let entry2 = format!("{} write batch latency", title_name); - let write_batch_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let write_batch_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_clear_journal_latency", var_name); let entry2 = format!("{} clear journal latency", title_name); - let clear_journal_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let clear_journal_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_connect_latency", var_name); let entry2 = format!("{} connect latency", title_name); - let connect_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let connect_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_open_shared_latency", var_name); let entry2 = format!("{} open shared partition", title_name); - let open_shared_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let open_shared_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_open_exclusive_latency", var_name); let entry2 = format!("{} open exclusive partition", title_name); - let open_exclusive_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let open_exclusive_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_list_all_latency", var_name); let entry2 = format!("{} list all latency", title_name); - let list_all_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let list_all_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_list_root_keys_latency", var_name); let entry2 = format!("{} list root keys latency", title_name); - let list_root_keys_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let list_root_keys_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_delete_all_latency", var_name); let entry2 = format!("{} delete all latency", title_name); - let delete_all_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let delete_all_latency = + register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_exists_latency", var_name); let entry2 = format!("{} exists latency", title_name); - let exists_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let exists_latency = register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_create_latency", var_name); let entry2 = format!("{} create latency", title_name); - let create_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let create_latency = register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_delete_latency", var_name); let entry2 = format!("{} delete latency", title_name); - let delete_latency = register_histogram_vec(&entry1, &entry2, &[], None); + let delete_latency = register_histogram_vec(&entry1, &entry2, &[], latency_buckets.clone()); let entry1 = format!("{}_read_value_none_cases", var_name); let entry2 = format!("{} read value none cases", title_name); @@ -166,66 +191,76 @@ impl KeyValueStoreMetrics { let entry1 = format!("{}_read_value_key_size", var_name); let entry2 = format!("{} read value key size", title_name); - let read_value_key_size = register_histogram_vec(&entry1, &entry2, &[], None); + let read_value_key_size = + register_histogram_vec(&entry1, &entry2, &[], size_buckets.clone()); let entry1 = format!("{}_read_value_value_size", var_name); let entry2 = format!("{} read value value size", title_name); - let read_value_value_size = register_histogram_vec(&entry1, &entry2, &[], None); + let read_value_value_size = + register_histogram_vec(&entry1, &entry2, &[], size_buckets.clone()); let entry1 = format!("{}_read_multi_values_num_entries", var_name); let entry2 = format!("{} read multi values num entries", title_name); - let read_multi_values_num_entries = register_histogram_vec(&entry1, &entry2, &[], None); + let read_multi_values_num_entries = + register_histogram_vec(&entry1, &entry2, &[], count_buckets.clone()); let entry1 = format!("{}_read_multi_values_key_sizes", var_name); let entry2 = format!("{} read multi values key sizes", title_name); - let read_multi_values_key_sizes = register_histogram_vec(&entry1, &entry2, &[], None); + let read_multi_values_key_sizes = + register_histogram_vec(&entry1, &entry2, &[], size_buckets.clone()); let entry1 = format!("{}_contains_keys_num_entries", var_name); let entry2 = format!("{} contains keys num entries", title_name); - let contains_keys_num_entries = register_histogram_vec(&entry1, &entry2, &[], None); + let contains_keys_num_entries = + register_histogram_vec(&entry1, &entry2, &[], count_buckets.clone()); let entry1 = format!("{}_contains_keys_key_sizes", var_name); let entry2 = format!("{} contains keys key sizes", title_name); - let contains_keys_key_sizes = register_histogram_vec(&entry1, &entry2, &[], None); + let contains_keys_key_sizes = + register_histogram_vec(&entry1, &entry2, &[], size_buckets.clone()); let entry1 = format!("{}_contains_key_key_size", var_name); let entry2 = format!("{} contains key key size", title_name); - let contains_key_key_size = register_histogram_vec(&entry1, &entry2, &[], None); + let contains_key_key_size = + register_histogram_vec(&entry1, &entry2, &[], size_buckets.clone()); let entry1 = format!("{}_find_keys_by_prefix_prefix_size", var_name); let entry2 = format!("{} find keys by prefix prefix size", title_name); - let find_keys_by_prefix_prefix_size = register_histogram_vec(&entry1, &entry2, &[], None); + let find_keys_by_prefix_prefix_size = + register_histogram_vec(&entry1, &entry2, &[], size_buckets.clone()); let entry1 = format!("{}_find_keys_by_prefix_num_keys", var_name); let entry2 = format!("{} find keys by prefix num keys", title_name); - let find_keys_by_prefix_num_keys = register_histogram_vec(&entry1, &entry2, &[], None); + let find_keys_by_prefix_num_keys = + register_histogram_vec(&entry1, &entry2, &[], count_buckets.clone()); let entry1 = format!("{}_find_keys_by_prefix_keys_size", var_name); let entry2 = format!("{} find keys by prefix keys size", title_name); - let find_keys_by_prefix_keys_size = register_histogram_vec(&entry1, &entry2, &[], None); + let find_keys_by_prefix_keys_size = + register_histogram_vec(&entry1, &entry2, &[], size_buckets.clone()); let entry1 = format!("{}_find_key_values_by_prefix_prefix_size", var_name); let entry2 = format!("{} find key values by prefix prefix size", title_name); let find_key_values_by_prefix_prefix_size = - register_histogram_vec(&entry1, &entry2, &[], None); + register_histogram_vec(&entry1, &entry2, &[], size_buckets.clone()); let entry1 = format!("{}_find_key_values_by_prefix_num_keys", var_name); let entry2 = format!("{} find key values by prefix num keys", title_name); let find_key_values_by_prefix_num_keys = - register_histogram_vec(&entry1, &entry2, &[], None); + register_histogram_vec(&entry1, &entry2, &[], count_buckets.clone()); let entry1 = format!("{}_find_key_values_by_prefix_key_values_size", var_name); let entry2 = format!("{} find key values by prefix key values size", title_name); let find_key_values_by_prefix_key_values_size = - register_histogram_vec(&entry1, &entry2, &[], None); + register_histogram_vec(&entry1, &entry2, &[], size_buckets.clone()); let entry1 = format!("{}_write_batch_size", var_name); let entry2 = format!("{} write batch size", title_name); - let write_batch_size = register_histogram_vec(&entry1, &entry2, &[], None); + let write_batch_size = register_histogram_vec(&entry1, &entry2, &[], size_buckets); let entry1 = format!("{}_list_all_sizes", var_name); let entry2 = format!("{} list all sizes", title_name); - let list_all_sizes = register_histogram_vec(&entry1, &entry2, &[], None); + let list_all_sizes = register_histogram_vec(&entry1, &entry2, &[], count_buckets); let entry1 = format!("{}_exists_true_cases", var_name); let entry2 = format!("{} exists true cases", title_name); diff --git a/linera-views/src/metrics.rs b/linera-views/src/metrics.rs index b80fef97eaf2..8b49e5abf4e0 100644 --- a/linera-views/src/metrics.rs +++ b/linera-views/src/metrics.rs @@ -44,3 +44,14 @@ pub static SAVE_VIEW_COUNTER: LazyLock = LazyLock::new(|| { &["type", "base_key"], ) }); + +/// The metric tracking the latency of saving views. +#[doc(hidden)] +pub static SAVE_VIEW_LATENCY: LazyLock = LazyLock::new(|| { + prometheus_util::register_histogram_vec( + "save_view_latency", + "Save view latency in milliseconds", + &["type"], + exponential_bucket_latencies(1000.0), + ) +});