Skip to main content

linera_views/
metrics.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::sync::LazyLock;
5
6// Re-export for macros.
7#[doc(hidden)]
8pub use linera_base::prometheus_util::{self, exponential_bucket_latencies};
9use prometheus::IntCounterVec;
10
11/// Increments the metrics counter with the given name, with the struct and base key as labels.
12pub fn increment_counter(counter: &LazyLock<IntCounterVec>, struct_name: &str, base_key: &[u8]) {
13    let base_key = hex::encode(base_key);
14    let labels = [struct_name, &base_key];
15    counter.with_label_values(&labels).inc();
16}
17
18linera_base::declare_metrics! {
19    /// The metric tracking the latency of the loading of views.
20    #[doc(hidden)]
21    pub static LOAD_VIEW_LATENCY: prometheus::HistogramVec =
22        prometheus_util::register_histogram_vec(
23            "load_view_latency",
24            "Load view latency in milliseconds",
25            &[],
26            exponential_bucket_latencies(1000.0),
27        );
28
29    /// The metric counting how often a view is read from storage.
30    #[doc(hidden)]
31    pub static LOAD_VIEW_COUNTER: IntCounterVec =
32        prometheus_util::register_int_counter_vec(
33            "load_view",
34            "The metric counting how often a view is read from storage",
35            &["type", "base_key"],
36        );
37
38    /// The metric counting how often a view is written from storage.
39    #[doc(hidden)]
40    pub static SAVE_VIEW_COUNTER: IntCounterVec =
41        prometheus_util::register_int_counter_vec(
42            "save_view",
43            "The metric counting how often a view is written from storage",
44            &["type", "base_key"],
45        );
46
47    /// The metric tracking the latency of saving views.
48    #[doc(hidden)]
49    pub static SAVE_VIEW_LATENCY: prometheus::HistogramVec =
50        prometheus_util::register_histogram_vec(
51            "save_view_latency",
52            "Save view latency in milliseconds",
53            &["type"],
54            exponential_bucket_latencies(1000.0),
55        );
56}
57
58#[cfg(test)]
59mod tests {
60    #[test]
61    fn label_free_metrics_are_exported_before_their_code_path_runs() {
62        crate::init_metrics();
63
64        let families = prometheus::gather();
65        let contains_keys = families
66            .iter()
67            .find(|family| family.get_name() == "linera_key_value_store_view_contains_keys_latency")
68            .expect("a label-free metric must be exported once init_metrics has run");
69
70        let histogram = contains_keys
71            .get_metric()
72            .first()
73            .expect("registering the vector must also create its single label-free child")
74            .get_histogram();
75        assert_eq!(histogram.get_sample_count(), 0);
76    }
77
78    /// Registration alone exports nothing — a vector emits one series per child, and a
79    /// labelled one has no children until a label combination is observed. This is why
80    /// forcing the `LazyLock` is not on its own enough, and why labelled metrics stay
81    /// workload-gated.
82    #[test]
83    fn labelled_metrics_stay_absent_until_a_label_combination_is_observed() {
84        crate::init_metrics();
85
86        let exported = prometheus::gather().iter().any(|family| {
87            family.get_name() == "linera_load_view" && !family.get_metric().is_empty()
88        });
89        assert!(!exported);
90    }
91}