use std::collections::HashMap;
use std::sync::Once;
use once_cell::sync::OnceCell;
use strum::{EnumIter, EnumVariantNames, IntoStaticStr};
use tracing::{instrument, Span};
use crate::metrics::{
HyperlightMetric, HyperlightMetricDefinition, HyperlightMetricEnum, HyperlightMetricType,
};
static INIT_METRICS: Once = Once::new();
static METRICS: OnceCell<HashMap<&'static str, HyperlightMetric>> = OnceCell::new();
static HYPERVISOR_METRIC_DEFINITIONS: &[HyperlightMetricDefinition] =
&[HyperlightMetricDefinition {
name: "number_of_cancelled_guest_executions",
help: "Number of guest executions that have been cancelled",
metric_type: HyperlightMetricType::IntCounter,
labels: &[],
buckets: &[],
}];
#[derive(Debug, EnumIter, EnumVariantNames, IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub(super) enum HypervisorMetric {
NumberOfCancelledGuestExecutions,
}
impl HyperlightMetricEnum<HypervisorMetric> for HypervisorMetric {
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
fn get_init_metrics() -> &'static Once {
&INIT_METRICS
}
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
fn get_metrics() -> &'static OnceCell<HashMap<&'static str, HyperlightMetric>> {
&METRICS
}
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
fn get_metric_definitions() -> &'static [HyperlightMetricDefinition] {
HYPERVISOR_METRIC_DEFINITIONS
}
}
#[cfg(test)]
mod tests {
use lazy_static::lazy_static;
use prometheus::Registry;
use strum::{IntoEnumIterator, VariantNames};
use super::*;
use crate::metrics::get_metrics_registry;
use crate::metrics::tests::HyperlightMetricEnumTest;
use crate::{int_counter_get, int_counter_inc, int_counter_inc_by, int_counter_reset};
impl HyperlightMetricEnumTest<HypervisorMetric> for HypervisorMetric {
fn get_enum_variant_names() -> &'static [&'static str] {
HypervisorMetric::VARIANTS
}
}
#[test]
fn test_enum_has_variant_for_all_metrics() {
<super::HypervisorMetric as HyperlightMetricEnumTest<HypervisorMetric>>::enum_has_variant_for_all_metrics();
}
#[test]
fn test_metric_definitions() {
<super::HypervisorMetric as HyperlightMetricEnumTest<HypervisorMetric>>::check_metric_definitions();
}
#[test]
#[ignore]
fn test_metrics() {
let iter: HypervisorMetricIter = HypervisorMetric::iter();
for sandbox_metric in iter {
match sandbox_metric.get_hyperlight_metric() {
Ok(hyperlight_metric) => match hyperlight_metric {
HyperlightMetric::IntCounter(int_counter) => {
let counter =
<super::HypervisorMetric as HyperlightMetricEnumTest<
HypervisorMetric,
>>::get_intcounter_metric(int_counter.name);
assert!(counter.is_ok());
let counter = counter.unwrap();
int_counter_reset!(&sandbox_metric);
assert_eq!(counter.get(), 0);
int_counter_inc!(&sandbox_metric);
assert_eq!(counter.get(), 1);
int_counter_inc_by!(&sandbox_metric, 5);
assert_eq!(counter.get(), 6);
int_counter_reset!(&sandbox_metric);
assert_eq!(counter.get(), 0);
let result = int_counter_get!(&sandbox_metric);
assert_eq!(result, 0);
}
_ => {
panic!("metric is not an IntCounter");
}
},
Err(e) => {
panic!("error getting metric: {}", e);
}
}
}
}
#[test]
#[ignore]
fn test_gather_metrics() {
lazy_static! {
static ref REGISTRY: Registry = Registry::default();
}
test_metrics();
let registry = get_metrics_registry();
let result = registry.gather();
assert_eq!(result.len(), 1);
}
}