hyperlight_host/metrics/
histogram_vec.rs

1/*
2Copyright 2024 The Hyperlight Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17use prometheus::{register_histogram_vec_with_registry, HistogramVec as PHistogramVec};
18use tracing::{instrument, Span};
19
20use super::{
21    get_histogram_opts, get_metrics_registry, GetHyperlightMetric, HyperlightMetric,
22    HyperlightMetricOps,
23};
24use crate::{new_error, HyperlightError, Result};
25
26/// A named bundle of histograms
27#[derive(Debug)]
28pub struct HistogramVec {
29    histogram: PHistogramVec,
30    /// The name of the histogram vec
31    pub name: &'static str,
32}
33
34impl HistogramVec {
35    /// Creates a new histogram vec and registers it with the metric registry
36    #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
37    pub fn new(name: &'static str, help: &str, labels: &[&str], buckets: Vec<f64>) -> Result<Self> {
38        let registry = get_metrics_registry();
39        let opts = get_histogram_opts(name, help, buckets);
40        let histogram = register_histogram_vec_with_registry!(opts, labels, registry)?;
41        Ok(Self { histogram, name })
42    }
43
44    /// Observes a value for a HistogramVec
45    #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
46    pub fn observe(&self, label_vals: &[&str], val: f64) -> Result<()> {
47        self.histogram
48            .get_metric_with_label_values(label_vals)?
49            .observe(val);
50        Ok(())
51    }
52
53    /// Gets the sum of values of an HistogramVec
54    #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
55    pub fn get_sample_sum(&self, label_vals: &[&str]) -> Result<f64> {
56        Ok(self
57            .histogram
58            .get_metric_with_label_values(label_vals)?
59            .get_sample_sum())
60    }
61
62    /// Gets the count of values of an HistogramVec
63    #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
64    pub fn get_sample_count(&self, label_vals: &[&str]) -> Result<u64> {
65        Ok(self
66            .histogram
67            .get_metric_with_label_values(label_vals)?
68            .get_sample_count())
69    }
70}
71
72impl<S: HyperlightMetricOps> GetHyperlightMetric<HistogramVec> for S {
73    #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
74    fn metric(&self) -> Result<&HistogramVec> {
75        let metric = self.get_metric()?;
76        <&HyperlightMetric as TryInto<&HistogramVec>>::try_into(metric)
77    }
78}
79
80impl<'a> TryFrom<&'a HyperlightMetric> for &'a HistogramVec {
81    type Error = HyperlightError;
82    #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
83    fn try_from(metric: &'a HyperlightMetric) -> Result<Self> {
84        match metric {
85            HyperlightMetric::HistogramVec(histogram) => Ok(histogram),
86            _ => Err(new_error!("metric is not a HistogramVec")),
87        }
88    }
89}
90
91impl From<HistogramVec> for HyperlightMetric {
92    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
93    fn from(histogram_vec: HistogramVec) -> Self {
94        HyperlightMetric::HistogramVec(histogram_vec)
95    }
96}
97
98/// Observes a value for a HistogramVec
99#[macro_export]
100macro_rules! histogram_vec_observe {
101    ($metric:expr, $label_vals:expr, $val:expr) => {{
102        match $crate::metrics::GetHyperlightMetric::<$crate::metrics::HistogramVec>::metric($metric)
103        {
104            Ok(val) => {
105                if let Err(e) = val.observe($label_vals, $val) {
106                    log::error!(
107                        "error calling observe with {} on metric with labels: {} {:?}",
108                        $val,
109                        e,
110                        $label_vals
111                    )
112                }
113            }
114            Err(e) => log::error!("error getting metric: {}", e),
115        };
116    }};
117}
118
119/// Gets the sum of values of an HistogramVec or logs an error if the metric is not found
120/// Returns 0.0 if the metric is not found
121#[macro_export]
122macro_rules! histogram_vec_sample_sum {
123    ($metric:expr, $label_vals:expr) => {{
124        match $crate::metrics::GetHyperlightMetric::<$crate::metrics::HistogramVec>::metric($metric)
125        {
126            Ok(val) => match val.get_sample_sum($label_vals) {
127                Ok(val) => val,
128                Err(e) => {
129                    log::error!(
130                        "error getting samples sum of metric with labels: {} {:?}",
131                        e,
132                        $label_vals
133                    );
134                    0.0
135                }
136            },
137
138            Err(e) => {
139                log::error!("error getting metric: {}", e);
140                0.0
141            }
142        }
143    }};
144}
145
146/// Gets the count of values of an HistogramVec or logs an error if the metric is not found
147/// Returns 0 if the metric is not found
148#[macro_export]
149macro_rules! histogram_vec_sample_count {
150    ($metric:expr, $label_vals:expr) => {{
151        match $crate::metrics::GetHyperlightMetric::<$crate::metrics::HistogramVec>::metric($metric)
152        {
153            Ok(val) => match val.get_sample_count($label_vals) {
154                Ok(val) => val,
155                Err(e) => {
156                    log::error!(
157                        "error getting samples count of metric with labels: {} {:?}",
158                        e,
159                        $label_vals
160                    );
161                    0
162                }
163            },
164
165            Err(e) => {
166                log::error!("error getting metric: {}", e);
167                0
168            }
169        }
170    }};
171}
172
173/// Observe the time it takes to execute an expression, record that time in microseconds in a
174/// `HistogramVec`, and return the result of that expression
175#[macro_export]
176macro_rules! histogram_vec_time_micros {
177    ($metric:expr, $label_vals:expr, $expr:expr) => {{
178        let start = std::time::Instant::now();
179        let result = $expr;
180        $crate::histogram_vec_observe!($metric, $label_vals, start.elapsed().as_micros() as f64);
181        result
182    }};
183}