Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .github/workflows/CargoPublish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,6 @@ jobs:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_PUBLISH_TOKEN }}
if: env.PUBLISH_HYPERLIGHT_COMMON != 'false'

- name: Publish hyperlight-guest-tracing-macro
continue-on-error: ${{ inputs.dry_run }}
run: cargo publish --manifest-path ./src/hyperlight_guest_tracing_macro/Cargo.toml ${{ inputs.dry_run && '--dry-run' || '' }}
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_PUBLISH_TOKEN }}
if: env.PUBLISH_HYPERLIGHT_GUEST_TRACING_MACRO != 'false'

- name: Publish hyperlight-guest-tracing
continue-on-error: ${{ inputs.dry_run }}
run: cargo publish --manifest-path ./src/hyperlight_guest_tracing/Cargo.toml ${{ inputs.dry_run && '--dry-run' || '' }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dep_rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ jobs:
cargo check -p hyperlight-host --features crashdump
cargo check -p hyperlight-host --features print_debug
cargo check -p hyperlight-host --features gdb
cargo check -p hyperlight-host --features trace_guest,unwind_guest,mem_profile
cargo check -p hyperlight-host --features trace_guest,mem_profile

# without any features
just test-compilation-no-default-features ${{ matrix.config }}
Expand Down
92 changes: 82 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ members = [
"src/hyperlight_host",
"src/hyperlight_guest_capi",
"src/hyperlight_guest_tracing",
"src/hyperlight_guest_tracing_macro",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we keep it around, but as deprecated, shimming the new API? so that we don't break anyone who was already using this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think this is the way to go. But I don't think we'll ever use it again

"src/hyperlight_testing",
"fuzz",
"src/hyperlight_guest_bin",
Expand Down Expand Up @@ -42,7 +41,6 @@ hyperlight-guest = { path = "src/hyperlight_guest", version = "0.9.0", default-f
hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.9.0", default-features = false }
hyperlight-testing = { path = "src/hyperlight_testing", default-features = false }
hyperlight-guest-tracing = { path = "src/hyperlight_guest_tracing", version = "0.9.0", default-features = false }
hyperlight-guest-tracing-macro = { path = "src/hyperlight_guest_tracing_macro", version = "0.9.0", default-features = false }
hyperlight-component-util = { path = "src/hyperlight_component_util", version = "0.9.0", default-features = false }
hyperlight-component-macro = { path = "src/hyperlight_component_macro", version = "0.9.0", default-features = false }

Expand Down
14 changes: 2 additions & 12 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ test-like-ci config=default-target hypervisor="kvm":
cargo check -p hyperlight-host --features crashdump
cargo check -p hyperlight-host --features print_debug
cargo check -p hyperlight-host --features gdb
cargo check -p hyperlight-host --features trace_guest,unwind_guest,mem_profile
cargo check -p hyperlight-host --features trace_guest,mem_profile

@# without any driver (should fail to compile)
just test-compilation-no-default-features {{config}}
Expand Down Expand Up @@ -194,20 +194,10 @@ test-rust-crashdump target=default-target features="":
test-rust-tracing target=default-target features="":
# Run tests for the tracing guest and macro
cargo test -p hyperlight-guest-tracing --profile={{ if target == "debug" { "dev" } else { target } }}
cargo test -p hyperlight-guest-tracing-macro --profile={{ if target == "debug" { "dev" } else { target } }}

# Prepare the tracing guest for testing
# Build the tracing guest to ensure it builds with the tracing feature
just build-rust-guests {{ target }} trace_guest
just move-rust-guests {{ target }}
# Run hello-world example with tracing enabled to get the trace output
TRACE_OUTPUT="$(cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example hello-world --features {{ if features =="" {"trace_guest"} else { "trace_guest," + features } }})" && \
TRACE_FILE="$(echo "$TRACE_OUTPUT" | grep -oE 'Creating trace file at: [^ ]+' | awk -F': ' '{print $2}')" && \
echo "$TRACE_OUTPUT" && \
if [ -z "$TRACE_FILE" ]; then \
echo "Error: Could not extract trace file path from output." >&2 ; \
exit 1 ; \
fi && \
cargo run -p trace_dump ./{{ simpleguest_source }}/{{ target }}/simpleguest "$TRACE_FILE" list_frames

# Rebuild the tracing guests without the tracing feature
# This is to ensure that the tracing feature does not affect the other tests
Expand Down
25 changes: 18 additions & 7 deletions docs/hyperlight-metrics-logs-and-traces.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,11 @@ Once the container or the exe is running, the trace output can be viewed in the

## Guest Tracing, Unwinding, and Memory Profiling

Hyperlight provides advanced observability features for guest code running inside micro virtual machines. You can enable guest-side tracing, stack unwinding, and memory profiling using the `trace_guest`, `unwind_guest`, and `mem_profile` features. This section explains how to build, run, and inspect guest traces.
Hyperlight provides advanced observability features for guest code running inside micro virtual machines. You can enable guest-side tracing, stack unwinding, and memory profiling using the `trace_guest` and `mem_profile` features. This section explains how to build, run, and inspect guest traces.

The following features are available for guest tracing:
- `trace_guest`: Enables tracing for guest code, capturing function calls and execution time.
- `unwind_guest`: Enables stack unwinding for guest code, allowing you to capture stack traces.
- `mem_profile`: Enables memory profiling for guest code, capturing memory allocations and usage.
- `mem_profile`: Enables memory profiling for guest code with stack unwinding, capturing memory allocations and usage.

### Building a Guest with Tracing Support

Expand All @@ -112,17 +111,29 @@ just move-rust-guests debug

This will build the guest binaries with the `trace_guest` feature enabled and move them to the appropriate location for use by the host.

**NOTE**: To enable the tracing in your application you need to use the `trace_guest` feature on the `hyperlight-guest-bin` and `hyperlight-guest` crates.

### Running a Hyperlight Example with Guest Tracing

Once the guest is built, you can run a Hyperlight example with guest tracing enabled. For example:

```bash
cargo run --example hello-world --features trace_guest
RUST_LOG="info,hyperlight_host::sandbox=info,hyperlight_guest=trace,hyperlight_guest_bin=trace" cargo run --example tracing-otlp --features trace_guest
```

This will execute the `hello-world` example, loading the guest with tracing enabled. During execution, trace data will be collected and written to a file in the `trace` directory.
This will execute the `tracing-otlp` example, loading the guest with tracing enabled.
During execution, trace data will be collected on the host and exported as opentelemetry spans/events.

You can set up a collector to gather all the traces and inspect the traces from both host and guests.

Due to the nature of execution inside a Sandbox, on a call basis, the guest tracing sets up a stack of spans to keep track of the correct parents for the incoming
guest spans.
We start with `call-to-guest` which contains all the spans coming from a guest. Additionally, for each exit into the host, we add another layer marking it with
a `call-to-host` span to follow the execution in the host and correctly set it as a child of the active span in the guest.
This logic simulates the propagation of Opentelemetry context that is usually done between two services, but cannot be done here seamlessly because the guest side
runs `no_std` which `opentelemetry` doesn't know.

### Inspecting Guest Trace Files
### Inspecting Guest memory Trace Files (for mem_profile)

To inspect the trace file generated by the guest, use the `trace_dump` crate. You will need the path to the guest symbols and the trace file. Run the following command:

Expand All @@ -140,7 +151,7 @@ This command will list the stack frames and tracing information captured during
cargo run -p trace_dump ./src/tests/rust_guests/bin/debug/simpleguest ./trace/<UUID>.trace list_frames
```

You can use additional features such as `unwind_guest` and `mem_profile` by enabling them during the build and run steps.
You can use the `mem_profile` additional feature by enabling them during the build and run steps.

> **Note:** Make sure to follow the build and run steps in order, and ensure that the guest binaries are up to date before running the host example.

Expand Down
1 change: 0 additions & 1 deletion src/hyperlight_common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ spin = "0.10.0"
default = ["tracing"]
fuzzing = ["dep:arbitrary"]
trace_guest = []
unwind_guest = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to this feature?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I merged it into the mem_profile one as it is only used there and it increases the number of combinations we need to test in CI

mem_profile = []
std = []

Expand Down
15 changes: 5 additions & 10 deletions src/hyperlight_common/src/outb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,23 +90,20 @@ impl TryFrom<u8> for Exception {
/// - CallFunction: makes a call to a host function,
/// - Abort: aborts the execution of the guest,
/// - DebugPrint: prints a message to the host
/// - TraceRecordStack: records the stack trace of the guest
/// - TraceBatch: reports a batch of spans and vents from the guest
/// - TraceMemoryAlloc: records memory allocation events
/// - TraceMemoryFree: records memory deallocation events
/// - TraceRecord: records a trace event in the guest
pub enum OutBAction {
Log = 99,
CallFunction = 101,
Abort = 102,
DebugPrint = 103,
#[cfg(feature = "unwind_guest")]
TraceRecordStack = 104,
#[cfg(feature = "trace_guest")]
TraceBatch = 104,
#[cfg(feature = "mem_profile")]
TraceMemoryAlloc = 105,
#[cfg(feature = "mem_profile")]
TraceMemoryFree = 106,
#[cfg(feature = "trace_guest")]
TraceRecord = 107,
}

impl TryFrom<u16> for OutBAction {
Expand All @@ -117,14 +114,12 @@ impl TryFrom<u16> for OutBAction {
101 => Ok(OutBAction::CallFunction),
102 => Ok(OutBAction::Abort),
103 => Ok(OutBAction::DebugPrint),
#[cfg(feature = "unwind_guest")]
104 => Ok(OutBAction::TraceRecordStack),
#[cfg(feature = "trace_guest")]
104 => Ok(OutBAction::TraceBatch),
#[cfg(feature = "mem_profile")]
105 => Ok(OutBAction::TraceMemoryAlloc),
#[cfg(feature = "mem_profile")]
106 => Ok(OutBAction::TraceMemoryFree),
#[cfg(feature = "trace_guest")]
107 => Ok(OutBAction::TraceRecord),
_ => Err(anyhow::anyhow!("Invalid OutBAction value: {}", val)),
}
}
Expand Down
1 change: 1 addition & 0 deletions src/hyperlight_guest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
hyperlight-common = { workspace = true }
hyperlight-guest-tracing = { workspace = true, default-features = false }
flatbuffers = { version= "25.2.10", default-features = false }
tracing = { version = "0.1.41", default-features = false, features = ["attributes"] }

[features]
default = []
Expand Down
Loading
Loading