Skip to content

Commit 937173f

Browse files
committed
Rework metrics to use metrics crate
Signed-off-by: Ludvig Liljenberg <lliljenberg@microsoft.com>
1 parent f67cf90 commit 937173f

File tree

19 files changed

+568
-1855
lines changed

19 files changed

+568
-1855
lines changed

Cargo.lock

Lines changed: 420 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/hyperlight_host/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ lazy_static = "1.4.0"
3434
serde = { version = "1.0", features = ["derive"] }
3535
serde_json = "1.0"
3636
log = "0.4.26"
37-
once_cell = { version = "1.21.1" }
3837
tracing = { version = "0.1.41", features = ["log"] }
3938
tracing-log = "0.2.0"
4039
tracing-core = "0.1.33"
@@ -43,11 +42,10 @@ vmm-sys-util = "0.12.1"
4342
crossbeam = "0.8.0"
4443
crossbeam-channel = "0.5.14"
4544
thiserror = "2.0.12"
46-
prometheus = "0.13.3"
47-
strum = { version = "0.27", features = ["derive"] }
4845
tempfile = { version = "3.18", optional = true }
4946
serde_yaml = "0.9"
5047
anyhow = "1.0"
48+
metrics = "0.24.1"
5149

5250
[target.'cfg(windows)'.dependencies]
5351
windows = { version = "0.59", features = [
@@ -104,6 +102,8 @@ opentelemetry_sdk = { version = "0.28", features = ["rt-tokio"] }
104102
tokio = { version = "1.43.0", features = ["full"] }
105103
criterion = "0.5.1"
106104
tracing-chrome = "0.7.2"
105+
metrics-util = "0.19.0"
106+
metrics-exporter-prometheus = "0.16.2"
107107

108108
[target.'cfg(windows)'.dev-dependencies]
109109
windows = { version = "0.59", features = [
@@ -119,7 +119,7 @@ cfg_aliases = "0.2.1"
119119
built = { version = "0.7.7", features = ["chrono", "git2"] }
120120

121121
[features]
122-
default = ["kvm", "mshv2", "seccomp"]
122+
default = ["kvm", "mshv2", "seccomp", "function_call_metrics"]
123123
seccomp = ["dep:seccompiler"]
124124
function_call_metrics = []
125125
executable_heap = []

src/hyperlight_host/examples/metrics/main.rs

Lines changed: 23 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,27 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, Ret
2222
use hyperlight_host::sandbox::uninitialized::UninitializedSandbox;
2323
use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox;
2424
use hyperlight_host::sandbox_state::transition::Noop;
25-
use hyperlight_host::{set_metrics_registry, GuestBinary, MultiUseSandbox, Result};
25+
use hyperlight_host::{GuestBinary, MultiUseSandbox, Result};
2626
use hyperlight_testing::simple_guest_as_string;
27-
use lazy_static::lazy_static;
28-
use prometheus::Registry;
2927

30-
lazy_static! {
31-
static ref HOST_REGISTRY: Registry = Registry::new();
32-
}
33-
fn fn_writer(_msg: String) -> Result<i32> {
34-
Ok(0)
28+
fn main() {
29+
// Install prometheus metrics exporter.
30+
// We only install the metrics recorder here, but you can also use the
31+
// `metrics_exporter_prometheus::PrometheusBuilder::new().install()` method
32+
// to install a HTTP listener that serves the metrics.
33+
let prometheus_handle = metrics_exporter_prometheus::PrometheusBuilder::new()
34+
.install_recorder()
35+
.expect("Failed to install Prometheus exporter");
36+
37+
// Do some hyperlight stuff to generate metrics.
38+
do_hyperlight_stuff();
39+
40+
// Get the metrics and print them in prometheus exposition format.
41+
let payload = prometheus_handle.render();
42+
println!("Prometheus metrics:\n{}", payload);
3543
}
3644

37-
fn main() -> Result<()> {
38-
// If this is not called then the default registry `prometheus::default_registry` will be used.
39-
set_metrics_registry(&HOST_REGISTRY)?;
40-
45+
fn do_hyperlight_stuff() {
4146
// Get the path to a simple guest binary.
4247
let hyperlight_guest_path =
4348
simple_guest_as_string().expect("Cannot find the guest binary at the expected location.");
@@ -60,7 +65,7 @@ fn main() -> Result<()> {
6065

6166
let no_op = Noop::<UninitializedSandbox, MultiUseSandbox>::default();
6267

63-
let mut multiuse_sandbox = usandbox.evolve(no_op)?;
68+
let mut multiuse_sandbox = usandbox.evolve(no_op).expect("Failed to evolve sandbox");
6469

6570
// Call a guest function 5 times to generate some metrics.
6671
for _ in 0..5 {
@@ -97,13 +102,14 @@ fn main() -> Result<()> {
97102
None,
98103
None,
99104
None,
100-
)?;
105+
)
106+
.expect("Failed to create UninitializedSandbox");
101107

102108
// Initialize the sandbox.
103109

104110
let no_op = Noop::<UninitializedSandbox, MultiUseSandbox>::default();
105111

106-
let mut multiuse_sandbox = usandbox.evolve(no_op)?;
112+
let mut multiuse_sandbox = usandbox.evolve(no_op).expect("Failed to evolve sandbox");
107113

108114
// Call a function that gets cancelled by the host function 5 times to generate some metrics.
109115

@@ -121,73 +127,8 @@ fn main() -> Result<()> {
121127
let result = join_handle.join();
122128
assert!(result.is_ok());
123129
}
124-
125-
get_metrics();
126-
127-
Ok(())
128130
}
129131

130-
fn get_metrics() {
131-
// Get the metrics from the registry.
132-
133-
let metrics = HOST_REGISTRY.gather();
134-
135-
// Print the metrics.
136-
137-
print!("\nMETRICS:\n");
138-
139-
for metric in metrics.iter() {
140-
match metric.get_field_type() {
141-
prometheus::proto::MetricType::COUNTER => {
142-
println!("Counter: {:?}", metric.get_help());
143-
metric.get_metric().iter().for_each(|metric| {
144-
let pair = metric.get_label();
145-
for pair in pair.iter() {
146-
println!("Label: {:?} Name: {:?}", pair.get_name(), pair.get_value());
147-
}
148-
println!("Value: {:?}", metric.get_counter().get_value());
149-
});
150-
}
151-
prometheus::proto::MetricType::GAUGE => {
152-
println!("Gauge: {:?}", metric.get_help());
153-
metric.get_metric().iter().for_each(|metric| {
154-
let pair = metric.get_label();
155-
for pair in pair.iter() {
156-
println!("Label: {:?} Name: {:?}", pair.get_name(), pair.get_value());
157-
}
158-
println!("Value: {:?}", metric.get_gauge().get_value());
159-
});
160-
}
161-
prometheus::proto::MetricType::UNTYPED => {
162-
println!("Metric: {:?}", metric.get_help());
163-
}
164-
prometheus::proto::MetricType::HISTOGRAM => {
165-
println!("Histogram: {:?}", metric.get_help());
166-
for metric in metric.get_metric() {
167-
let pair = metric.get_label();
168-
for pair in pair.iter() {
169-
println!("Label: {:?} Name: {:?}", pair.get_name(), pair.get_value());
170-
}
171-
let count = metric.get_histogram().get_sample_count();
172-
println!("Number of observations: {:?}", count);
173-
let sm = metric.get_histogram().get_sample_sum();
174-
println!("Sum of observations: {:?}", sm);
175-
metric
176-
.get_histogram()
177-
.get_bucket()
178-
.iter()
179-
.for_each(|bucket| {
180-
println!(
181-
"Bucket: {:?} Count: {:?}",
182-
bucket.get_upper_bound(),
183-
bucket.get_cumulative_count()
184-
)
185-
});
186-
}
187-
}
188-
prometheus::proto::MetricType::SUMMARY => {
189-
println!("Summary: {:?}", metric.get_help());
190-
}
191-
}
192-
}
132+
fn fn_writer(_msg: String) -> Result<i32> {
133+
Ok(0)
193134
}

src/hyperlight_host/src/error.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,6 @@ pub enum HyperlightError {
237237
#[error("Failure processing PE File {0:?}")]
238238
PEFileProcessingFailure(#[from] goblin::error::Error),
239239

240-
/// a Prometheus error occurred
241-
#[error("Prometheus Error {0:?}")]
242-
Prometheus(#[from] prometheus::Error),
243-
244240
/// Raw pointer is less than base address
245241
#[error("Raw pointer ({0:?}) was less than the base address ({1})")]
246242
RawPointerLessThanBaseAddress(RawPtr, u64),

src/hyperlight_host/src/func/guest_err.rs

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,13 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
use hyperlight_common::flatbuffer_wrappers::guest_error::{
18-
ErrorCode, GuestError as GuestErrorStruct,
19-
};
17+
use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode;
2018

2119
use crate::error::HyperlightError::{GuestError, OutBHandlingError, StackOverflow};
2220
use crate::mem::shared_mem::HostSharedMemory;
21+
use crate::metrics::{self, CounterMetric};
2322
use crate::sandbox::mem_mgr::MemMgrWrapper;
24-
use crate::sandbox::metrics::SandboxMetric::GuestErrorCount;
25-
use crate::{int_counter_vec_inc, log_then_return, Result};
23+
use crate::{log_then_return, Result};
2624
/// Check for a guest error and return an `Err` if one was found,
2725
/// and `Ok` if one was not found.
2826
pub(crate) fn check_for_guest_error(mgr: &MemMgrWrapper<HostSharedMemory>) -> Result<()> {
@@ -31,7 +29,7 @@ pub(crate) fn check_for_guest_error(mgr: &MemMgrWrapper<HostSharedMemory>) -> Re
3129
ErrorCode::NoError => Ok(()),
3230
ErrorCode::OutbError => match mgr.as_ref().get_host_error()? {
3331
Some(host_err) => {
34-
increment_guest_error_count(&guest_err);
32+
metrics::increase_counter(CounterMetric::NumGuestErrors);
3533
log_then_return!(OutBHandlingError(
3634
host_err.source.clone(),
3735
guest_err.message.clone()
@@ -41,23 +39,15 @@ pub(crate) fn check_for_guest_error(mgr: &MemMgrWrapper<HostSharedMemory>) -> Re
4139
None => Ok(()),
4240
},
4341
ErrorCode::StackOverflow => {
44-
increment_guest_error_count(&guest_err.clone());
42+
metrics::increase_counter(CounterMetric::NumGuestErrors);
4543
log_then_return!(StackOverflow());
4644
}
4745
_ => {
48-
increment_guest_error_count(&guest_err.clone());
46+
metrics::increase_counter(CounterMetric::NumGuestErrors);
4947
log_then_return!(GuestError(
5048
guest_err.code.clone(),
5149
guest_err.message.clone()
5250
));
5351
}
5452
}
5553
}
56-
57-
fn increment_guest_error_count(guest_err: &GuestErrorStruct) {
58-
let guest_err_code_string: String = guest_err.code.clone().into();
59-
int_counter_vec_inc!(
60-
&GuestErrorCount,
61-
&[&guest_err_code_string, guest_err.message.clone().as_str()]
62-
);
63-
}

src/hyperlight_host/src/hypervisor/hypervisor_handler.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ use windows::Win32::System::Hypervisor::{WHvCancelRunVirtualProcessor, WHV_PARTI
3737

3838
#[cfg(gdb)]
3939
use super::gdb::create_gdb_thread;
40-
#[cfg(feature = "function_call_metrics")]
41-
use crate::histogram_vec_observe;
4240
#[cfg(gdb)]
4341
use crate::hypervisor::handlers::DbgMemAccessHandlerWrapper;
4442
use crate::hypervisor::handlers::{MemAccessHandlerWrapper, OutBHandlerWrapper};
@@ -53,8 +51,6 @@ use crate::mem::shared_mem::{GuestSharedMemory, HostSharedMemory, SharedMemory};
5351
#[cfg(gdb)]
5452
use crate::sandbox::config::DebugInfo;
5553
use crate::sandbox::hypervisor::{get_available_hypervisor, HypervisorType};
56-
#[cfg(feature = "function_call_metrics")]
57-
use crate::sandbox::metrics::SandboxMetric::GuestFunctionCallDurationMicroseconds;
5854
#[cfg(target_os = "linux")]
5955
use crate::signal_handlers::setup_signal_handlers;
6056
use crate::HyperlightError::{
@@ -438,6 +434,8 @@ impl HypervisorHandler {
438434
let res = {
439435
#[cfg(feature = "function_call_metrics")]
440436
{
437+
use crate::metrics::{self, HistogramMetric};
438+
441439
let start = std::time::Instant::now();
442440
let result = hv.dispatch_call_from_host(
443441
dispatch_function_addr,
@@ -447,11 +445,8 @@ impl HypervisorHandler {
447445
#[cfg(gdb)]
448446
configuration.dbg_mem_access_handler.clone(),
449447
);
450-
histogram_vec_observe!(
451-
&GuestFunctionCallDurationMicroseconds,
452-
&[function_name.as_str()],
453-
start.elapsed().as_micros() as f64
454-
);
448+
let elapsed = start.elapsed();
449+
metrics::record_histogram_duration(HistogramMetric::GuestCallDuration, elapsed);
455450
result
456451
}
457452

0 commit comments

Comments
 (0)