hypercall/observability/
prometheus.rs1use metrics::{describe_gauge, gauge};
7use metrics_exporter_prometheus::{PrometheusBuilder, PrometheusHandle};
8use std::sync::atomic::{AtomicBool, Ordering};
9use std::sync::OnceLock;
10use std::time::Duration;
11
12static PROM_HANDLE: OnceLock<PrometheusHandle> = OnceLock::new();
13static UPKEEP_STARTED: AtomicBool = AtomicBool::new(false);
14
15pub fn init_prometheus() -> &'static PrometheusHandle {
23 PROM_HANDLE.get_or_init(|| {
24 let handle = PrometheusBuilder::new()
25 .install_recorder()
26 .expect("failed to install Prometheus recorder");
27
28 tracing::info!("Prometheus metrics recorder initialized");
29 handle
30 })
31}
32
33pub fn start_upkeep_task() {
38 if UPKEEP_STARTED
39 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
40 .is_ok()
41 {
42 describe_gauge!(
44 "ht_process_memory_rss_bytes",
45 "Resident set size (physical memory) in bytes"
46 );
47 describe_gauge!(
48 "ht_process_memory_virtual_bytes",
49 "Virtual memory size in bytes"
50 );
51
52 let handle = init_prometheus().clone();
53 tokio::spawn(async move {
54 let mut interval = tokio::time::interval(Duration::from_secs(5));
55 loop {
56 interval.tick().await;
57 handle.run_upkeep();
58
59 if let Some(usage) = memory_stats::memory_stats() {
61 gauge!("ht_process_memory_rss_bytes").set(usage.physical_mem as f64);
62 gauge!("ht_process_memory_virtual_bytes").set(usage.virtual_mem as f64);
63 }
64 }
65 });
66 tracing::debug!("Prometheus upkeep task started");
67 }
68}
69
70pub fn render() -> String {
72 init_prometheus().render()
73}