use std::{cell::RefCell, collections::HashMap};
use crate::{
dispatcher::root_id,
hostcalls::{self, MetricType},
log_concern, Status,
};
#[derive(Default)]
pub struct MetricsInfo {
counters: HashMap<String, u32>,
gauges: HashMap<String, u32>,
histograms: HashMap<String, u32>,
}
thread_local! {
static METRICS: RefCell<HashMap<u32, MetricsInfo>> = RefCell::default();
}
#[derive(Clone, Copy, Debug)]
pub struct Counter(u32);
pub struct ConstCounter {
name: &'static str,
}
impl ConstCounter {
pub const fn define(name: &'static str) -> Self {
Self { name }
}
pub fn get(&self) -> Counter {
Counter::define(self.name)
}
}
impl Counter {
pub fn define(name: impl AsRef<str>) -> Self {
METRICS.with_borrow_mut(|metrics| {
let metrics = metrics.entry(root_id()).or_default();
if let Some(counter) = metrics.counters.get(name.as_ref()) {
return Self(*counter);
}
let out = log_concern(
"define-metric",
hostcalls::define_metric(MetricType::Counter, name.as_ref()),
);
metrics.counters.insert(name.as_ref().to_string(), out);
Self(out)
})
}
pub fn get(&self) -> Result<u64, Status> {
hostcalls::get_metric(self.0)
}
pub fn record(&self, value: u64) {
log_concern("record-metric", hostcalls::record_metric(self.0, value));
}
pub fn increment(&self, offset: i64) {
log_concern(
"increment-metric",
hostcalls::increment_metric(self.0, offset),
);
}
}
#[derive(Clone, Copy, Debug)]
pub struct Gauge(u32);
pub struct ConstGauge {
name: &'static str,
}
impl ConstGauge {
pub const fn define(name: &'static str) -> Self {
Self { name }
}
pub fn get(&self) -> Gauge {
Gauge::define(self.name)
}
}
impl Gauge {
pub fn define(name: impl AsRef<str>) -> Self {
METRICS.with_borrow_mut(|metrics| {
let metrics = metrics.entry(root_id()).or_default();
if let Some(gauge) = metrics.gauges.get(name.as_ref()) {
return Self(*gauge);
}
let out = log_concern(
"define-metric",
hostcalls::define_metric(MetricType::Gauge, name.as_ref()),
);
metrics.gauges.insert(name.as_ref().to_string(), out);
Self(out)
})
}
pub fn get(&self) -> Result<u64, Status> {
hostcalls::get_metric(self.0)
}
pub fn record(&self, value: u64) {
log_concern("record-metric", hostcalls::record_metric(self.0, value));
}
pub fn increment(&self, offset: i64) {
log_concern(
"increment-metric",
hostcalls::increment_metric(self.0, offset),
);
}
}
#[derive(Clone, Copy, Debug)]
pub struct Histogram(u32);
pub struct ConstHistogram {
name: &'static str,
}
impl ConstHistogram {
pub const fn define(name: &'static str) -> Self {
Self { name }
}
pub fn get(&self) -> Histogram {
Histogram::define(self.name)
}
}
impl Histogram {
pub fn define(name: impl AsRef<str>) -> Self {
METRICS.with_borrow_mut(|metrics| {
let metrics = metrics.entry(root_id()).or_default();
if let Some(histogram) = metrics.histograms.get(name.as_ref()) {
return Self(*histogram);
}
let out = log_concern(
"define-metric",
hostcalls::define_metric(MetricType::Histogram, name.as_ref()),
);
metrics.histograms.insert(name.as_ref().to_string(), out);
Self(out)
})
}
pub fn record(&self, value: u64) {
log_concern("record-metric", hostcalls::record_metric(self.0, value));
}
}