Skip to content

Commit 4918fcd

Browse files
authored
Fix issues in guest logging (#410)
* fix inconsistent logging crate names Signed-off-by: Simon Davies <[email protected]> * Allow explicit setting of max guest log level, check RUST_LOG to set guest log_level if not set The guest log level impacts the amount of logs produced by the guest, its presently set by examining the value of max_log_level in the host. This may not be appropriate since logging in the guest is expensive and it may cause logs to be emitted from the guest but ignored in the host. This change introduces a function on an uninitializedsandbox to set the level explicitly, if this is not set the env var RUST_LOG is parsed to determine the log level so that logs are only produced if they are going to be consumed. If RUST_LOG is not set then the max guest log level is set to error. Signed-off-by: Simon Davies <[email protected]> --------- Signed-off-by: Simon Davies <[email protected]>
1 parent 747aa10 commit 4918fcd

13 files changed

+136
-68
lines changed

Diff for: docs/hyperlight-metrics-logs-and-traces.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ In the [examples/tracing](../src/hyperlight_host/examples/tracing) directory, th
6666
#### Linux
6767

6868
```bash
69-
RUST_LOG='none,hyperlight-host=info,tracing=info' cargo run --example tracing
69+
RUST_LOG='none,hyperlight_host=info,tracing=info' cargo run --example tracing
7070
```
7171

7272
#### Windows
7373

7474
```powershell
75-
$env:RUST_LOG='none,hyperlight-host=info,tracing=info'; cargo run --example tracing
75+
$env:RUST_LOG='none,hyperlight_host=info,tracing=info'; cargo run --example tracing
7676
```
7777

7878
### Using OTLP exporter and Jaeger

Diff for: src/hyperlight_host/src/hypervisor/hyperv_linux.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ extern crate mshv_ioctls3 as mshv_ioctls;
2626

2727
use std::fmt::{Debug, Formatter};
2828

29-
use log::error;
29+
use log::{error, LevelFilter};
3030
#[cfg(mshv2)]
3131
use mshv_bindings::hv_message;
3232
#[cfg(gdb)]
@@ -463,8 +463,14 @@ impl Hypervisor for HypervLinuxDriver {
463463
outb_hdl: OutBHandlerWrapper,
464464
mem_access_hdl: MemAccessHandlerWrapper,
465465
hv_handler: Option<HypervisorHandler>,
466+
max_guest_log_level: Option<LevelFilter>,
466467
#[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper,
467468
) -> Result<()> {
469+
let max_guest_log_level: u64 = match max_guest_log_level {
470+
Some(level) => level as u64,
471+
None => self.get_max_log_level().into(),
472+
};
473+
468474
let regs = StandardRegisters {
469475
rip: self.entrypoint,
470476
rsp: self.orig_rsp.absolute()?,
@@ -474,7 +480,7 @@ impl Hypervisor for HypervLinuxDriver {
474480
rcx: peb_addr.into(),
475481
rdx: seed,
476482
r8: page_size.into(),
477-
r9: self.get_max_log_level().into(),
483+
r9: max_guest_log_level,
478484

479485
..Default::default()
480486
};

Diff for: src/hyperlight_host/src/hypervisor/hyperv_windows.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use std::fmt::{Debug, Formatter};
2020
use std::string::String;
2121

2222
use hyperlight_common::mem::PAGE_SIZE_USIZE;
23+
use log::LevelFilter;
2324
use tracing::{instrument, Span};
2425
use windows::Win32::System::Hypervisor::{
2526
WHvX64RegisterCr0, WHvX64RegisterCr3, WHvX64RegisterCr4, WHvX64RegisterCs, WHvX64RegisterEfer,
@@ -307,8 +308,14 @@ impl Hypervisor for HypervWindowsDriver {
307308
outb_hdl: OutBHandlerWrapper,
308309
mem_access_hdl: MemAccessHandlerWrapper,
309310
hv_handler: Option<HypervisorHandler>,
311+
max_guest_log_level: Option<LevelFilter>,
310312
#[cfg(gdb)] dbg_mem_access_hdl: DbgMemAccessHandlerWrapper,
311313
) -> Result<()> {
314+
let max_guest_log_level: u64 = match max_guest_log_level {
315+
Some(level) => level as u64,
316+
None => self.get_max_log_level().into(),
317+
};
318+
312319
let regs = WHvGeneralRegisters {
313320
rip: self.entrypoint,
314321
rsp: self.orig_rsp.absolute()?,
@@ -317,7 +324,7 @@ impl Hypervisor for HypervWindowsDriver {
317324
rcx: peb_address.into(),
318325
rdx: seed,
319326
r8: page_size.into(),
320-
r9: self.get_max_log_level().into(),
327+
r9: max_guest_log_level,
321328
rflags: 1 << 1, // eflags bit index 1 is reserved and always needs to be 1
322329

323330
..Default::default()

Diff for: src/hyperlight_host/src/hypervisor/hypervisor_handler.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crossbeam::atomic::AtomicCell;
2828
use crossbeam_channel::{Receiver, Sender};
2929
#[cfg(target_os = "linux")]
3030
use libc::{pthread_kill, pthread_self, ESRCH};
31-
use log::{error, info};
31+
use log::{error, info, LevelFilter};
3232
use tracing::{instrument, Span};
3333
#[cfg(target_os = "linux")]
3434
use vmm_sys_util::signal::SIGRTMIN;
@@ -191,6 +191,7 @@ pub(crate) struct HvHandlerConfig {
191191
pub(crate) outb_handler: OutBHandlerWrapper,
192192
pub(crate) mem_access_handler: MemAccessHandlerWrapper,
193193
pub(crate) max_wait_for_cancellation: Duration,
194+
pub(crate) max_guest_log_level: Option<LevelFilter>,
194195
#[cfg(gdb)]
195196
pub(crate) dbg_mem_access_handler: DbgMemAccessHandlerWrapper,
196197
}
@@ -360,6 +361,7 @@ impl HypervisorHandler {
360361
configuration.outb_handler.clone(),
361362
configuration.mem_access_handler.clone(),
362363
Some(hv_handler_clone.clone()),
364+
configuration.max_guest_log_level,
363365
#[cfg(gdb)]
364366
configuration.dbg_mem_access_handler.clone(),
365367
);

Diff for: src/hyperlight_host/src/hypervisor/inprocess.rs

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
use std::fmt::Debug;
1818
use std::os::raw::c_void;
1919

20+
use log::LevelFilter;
21+
2022
#[cfg(gdb)]
2123
use super::handlers::DbgMemAccessHandlerWrapper;
2224
use super::{HyperlightExit, Hypervisor};
@@ -75,6 +77,7 @@ impl<'a> Hypervisor for InprocessDriver<'a> {
7577
_outb_handle_fn: super::handlers::OutBHandlerWrapper,
7678
_mem_access_fn: super::handlers::MemAccessHandlerWrapper,
7779
_hv_handler: Option<super::hypervisor_handler::HypervisorHandler>,
80+
_guest_max_log_level: Option<LevelFilter>,
7881
#[cfg(gdb)] _dbg_mem_access_fn: DbgMemAccessHandlerWrapper,
7982
) -> crate::Result<()> {
8083
let entrypoint_fn: extern "win64" fn(u64, u64, u64, u64) =

Diff for: src/hyperlight_host/src/hypervisor/kvm.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::sync::{Arc, Mutex};
2222
use kvm_bindings::{kvm_fpu, kvm_regs, kvm_userspace_memory_region, KVM_MEM_READONLY};
2323
use kvm_ioctls::Cap::UserMemory;
2424
use kvm_ioctls::{Kvm, VcpuExit, VcpuFd, VmFd};
25+
use log::LevelFilter;
2526
use tracing::{instrument, Span};
2627

2728
use super::fpu::{FP_CONTROL_WORD_DEFAULT, FP_TAG_WORD_DEFAULT, MXCSR_DEFAULT};
@@ -406,8 +407,14 @@ impl Hypervisor for KVMDriver {
406407
outb_hdl: OutBHandlerWrapper,
407408
mem_access_hdl: MemAccessHandlerWrapper,
408409
hv_handler: Option<HypervisorHandler>,
410+
max_guest_log_level: Option<LevelFilter>,
409411
#[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper,
410412
) -> Result<()> {
413+
let max_guest_log_level: u64 = match max_guest_log_level {
414+
Some(level) => level as u64,
415+
None => self.get_max_log_level().into(),
416+
};
417+
411418
let regs = kvm_regs {
412419
rip: self.entrypoint,
413420
rsp: self.orig_rsp.absolute()?,
@@ -416,7 +423,7 @@ impl Hypervisor for KVMDriver {
416423
rcx: peb_addr.into(),
417424
rdx: seed,
418425
r8: page_size.into(),
419-
r9: self.get_max_log_level().into(),
426+
r9: max_guest_log_level,
420427

421428
..Default::default()
422429
};

Diff for: src/hyperlight_host/src/hypervisor/mod.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
use log::LevelFilter;
1718
use tracing::{instrument, Span};
1819

1920
use crate::error::HyperlightError::ExecutionCanceledByHost;
@@ -63,6 +64,7 @@ pub(crate) mod wrappers;
6364
pub(crate) mod crashdump;
6465

6566
use std::fmt::Debug;
67+
use std::str::FromStr;
6668
use std::sync::{Arc, Mutex};
6769

6870
#[cfg(gdb)]
@@ -130,6 +132,7 @@ pub(crate) trait Hypervisor: Debug + Sync + Send {
130132
outb_handle_fn: OutBHandlerWrapper,
131133
mem_access_fn: MemAccessHandlerWrapper,
132134
hv_handler: Option<HypervisorHandler>,
135+
guest_max_log_level: Option<LevelFilter>,
133136
#[cfg(gdb)] dbg_mem_access_fn: DbgMemAccessHandlerWrapper,
134137
) -> Result<()>;
135138

@@ -191,7 +194,39 @@ pub(crate) trait Hypervisor: Debug + Sync + Send {
191194

192195
/// Get the logging level to pass to the guest entrypoint
193196
fn get_max_log_level(&self) -> u32 {
194-
log::max_level() as u32
197+
// Check to see if the RUST_LOG environment variable is set
198+
// and if so, parse it to get the log_level for hyperlight_guest
199+
// if that is not set get the log level for the hyperlight_host
200+
201+
// This is done as the guest will produce logs based on the log level returned here
202+
// producing those logs is expensive and we don't want to do it if the host is not
203+
// going to process them
204+
205+
let val = std::env::var("RUST_LOG").unwrap_or_default();
206+
207+
let level = if val.contains("hyperlight_guest") {
208+
val.split(',')
209+
.find(|s| s.contains("hyperlight_guest"))
210+
.unwrap_or("")
211+
.split('=')
212+
.nth(1)
213+
.unwrap_or("")
214+
} else if val.contains("hyperlight_host") {
215+
val.split(',')
216+
.find(|s| s.contains("hyperlight_host"))
217+
.unwrap_or("")
218+
.split('=')
219+
.nth(1)
220+
.unwrap_or("")
221+
} else {
222+
// look for a value string that does not contain "="
223+
val.split(',').find(|s| !s.contains("=")).unwrap_or("")
224+
};
225+
226+
log::info!("Determined guest log level: {}", level);
227+
// Convert the log level string to a LevelFilter
228+
// If no value is found, default to Error
229+
LevelFilter::from_str(level).unwrap_or(LevelFilter::Error) as u32
195230
}
196231

197232
/// get a mutable trait object from self
@@ -356,6 +391,7 @@ pub(crate) mod tests {
356391
max_wait_for_cancellation: Duration::from_millis(
357392
SandboxConfiguration::DEFAULT_MAX_WAIT_FOR_CANCELLATION as u64,
358393
),
394+
max_guest_log_level: None,
359395
};
360396

361397
let mut hv_handler = HypervisorHandler::new(hv_handler_config);

Diff for: src/hyperlight_host/src/sandbox/outb.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub(super) fn outb_log(mgr: &mut SandboxMemoryManager<HostSharedMemory>) -> Resu
8888
&Record::builder()
8989
.args(format_args!("{}", log_data.message))
9090
.level(record_level)
91-
.target("hyperlight-guest")
91+
.target("hyperlight_guest")
9292
.file(source_file)
9393
.line(line)
9494
.module_path(source)
@@ -100,7 +100,7 @@ pub(super) fn outb_log(mgr: &mut SandboxMemoryManager<HostSharedMemory>) -> Resu
100100
&Record::builder()
101101
.args(format_args!("{}", log_data.message))
102102
.level(record_level)
103-
.target("hyperlight-guest")
103+
.target("hyperlight_guest")
104104
.file(Some(&log_data.source_file))
105105
.line(Some(log_data.line))
106106
.module_path(Some(&log_data.source))
@@ -442,7 +442,7 @@ mod tests {
442442
test_value_as_str(metadata_values_map, "level", expected_level);
443443
test_value_as_str(event_values_map, "log.file", "test source file");
444444
test_value_as_str(event_values_map, "log.module_path", "test source");
445-
test_value_as_str(event_values_map, "log.target", "hyperlight-guest");
445+
test_value_as_str(event_values_map, "log.target", "hyperlight_guest");
446446
count_matching_events += 1;
447447
}
448448
assert!(

Diff for: src/hyperlight_host/src/sandbox/uninitialized.rs

+10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use std::path::Path;
2020
use std::sync::{Arc, Mutex};
2121
use std::time::Duration;
2222

23+
use log::LevelFilter;
2324
use tracing::{instrument, Span};
2425

2526
#[cfg(gdb)]
@@ -54,6 +55,7 @@ pub struct UninitializedSandbox {
5455
pub(crate) max_initialization_time: Duration,
5556
pub(crate) max_execution_time: Duration,
5657
pub(crate) max_wait_for_cancellation: Duration,
58+
pub(crate) max_guest_log_level: Option<LevelFilter>,
5759
#[cfg(gdb)]
5860
pub(crate) debug_info: Option<DebugInfo>,
5961
}
@@ -195,6 +197,7 @@ impl UninitializedSandbox {
195197
max_wait_for_cancellation: Duration::from_millis(
196198
sandbox_cfg.get_max_wait_for_cancellation() as u64,
197199
),
200+
max_guest_log_level: None,
198201
#[cfg(gdb)]
199202
debug_info,
200203
};
@@ -299,6 +302,13 @@ impl UninitializedSandbox {
299302
SandboxMemoryManager::load_guest_binary_into_memory(cfg, &mut exe_info, inprocess)
300303
}
301304
}
305+
306+
/// Set the max log level to be used by the guest.
307+
/// If this is not set then the log level will be determined by parsing the RUST_LOG environment variable.
308+
/// If the RUST_LOG environment variable is not set then the max log level will be set to `LevelFilter::Error`.
309+
pub fn set_max_guest_log_level(&mut self, log_level: LevelFilter) {
310+
self.max_guest_log_level = Some(log_level);
311+
}
302312
}
303313
// Check to see if the current version of Windows is supported
304314
// Hyperlight is only supported on Windows 11 and Windows Server 2022 and later

Diff for: src/hyperlight_host/src/sandbox/uninitialized_evolve.rs

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
use core::time::Duration;
1818
use std::sync::{Arc, Mutex};
1919

20+
use log::LevelFilter;
2021
use rand::Rng;
2122
use tracing::{instrument, Span};
2223

@@ -70,6 +71,7 @@ where
7071
u_sbox.max_initialization_time,
7172
u_sbox.max_execution_time,
7273
u_sbox.max_wait_for_cancellation,
74+
u_sbox.max_guest_log_level,
7375
#[cfg(gdb)]
7476
u_sbox.debug_info,
7577
)?;
@@ -99,13 +101,15 @@ pub(super) fn evolve_impl_multi_use(u_sbox: UninitializedSandbox) -> Result<Mult
99101
}
100102

101103
#[instrument(err(Debug), skip_all, parent = Span::current(), level = "Trace")]
104+
#[allow(clippy::too_many_arguments)]
102105
fn hv_init(
103106
hshm: &MemMgrWrapper<HostSharedMemory>,
104107
gshm: SandboxMemoryManager<GuestSharedMemory>,
105108
host_funcs: Arc<Mutex<HostFuncsWrapper>>,
106109
max_init_time: Duration,
107110
max_exec_time: Duration,
108111
max_wait_for_cancellation: Duration,
112+
max_guest_log_level: Option<LevelFilter>,
109113
#[cfg(gdb)] debug_info: Option<DebugInfo>,
110114
) -> Result<HypervisorHandler> {
111115
let outb_hdl = outb_handler_wrapper(hshm.clone(), host_funcs);
@@ -134,6 +138,7 @@ fn hv_init(
134138
max_init_time,
135139
max_exec_time,
136140
max_wait_for_cancellation,
141+
max_guest_log_level,
137142
};
138143
// Note: `dispatch_function_addr` is set by the Hyperlight guest library, and so it isn't in
139144
// shared memory at this point in time. We will set it after the execution of `hv_init`.

0 commit comments

Comments
 (0)