How to Debug Issues in microsandbox: A Complete Guide to CLI, SDK, and Runtime Diagnostics
Enable debug logging in microsandbox using msb --log-level debug, set MICROSANDBOX_LOG=debug for SDKs, or use RUST_LOG=debug for Rust code, then inspect structured JSON logs in ~/.microsandbox/logs/ to trace VM boot sequences, network policy enforcement, and file-system operations.
The microsandbox project by SuperRad Company runs untrusted workloads inside lightweight micro-VMs. Debugging these sandboxed environments requires visibility across three distinct layers: the CLI tool, language SDKs, and the runtime agent. All layers funnel diagnostics through a unified structured tracing system based on the tracing crate, writing JSON-lines to log files you can filter with standard tools.
Enable Debug Logging in microsandbox
CLI Debugging with msb
The msb CLI accepts a --log-level flag that forwards the level to the runtime via the MICROSANDBOX_LOG environment variable. In [crates/cli/src/main.rs](https://github.com/superradcompany/microsandbox/blob/main/crates/cli/src/main.rs), the argument parsing handles this delegation.
# Maximum verbosity for every traced event
msb --log-level debug run python -- python -c "print('hi')"
Valid levels include error, warn, info, debug, and trace. The debug level captures VM boot sequences, image pulling, and RPC messages without overwhelming output.
SDK Debugging: Rust
The Rust SDK honors the standard RUST_LOG environment variable. The tracing subscriber initialization occurs in [crates/metrics-collector/bin/main.rs](https://github.com/superradcompany/microsandbox/blob/main/crates/metrics-collector/bin/main.rs), where env-var overrides apply before the subscriber is installed.
RUST_LOG=debug cargo run --example sandbox_demo
You can also set the variable programmatically before initializing the subscriber:
std::env::set_var("RUST_LOG", "microsandbox=debug,network=trace");
tracing_subscriber::fmt::init();
SDK Debugging: Python, TypeScript, and Go
All non-Rust SDKs read the MICROSANDBOX_LOG environment variable during native startup:
| SDK | Setup location | Usage |
|---|---|---|
| Python | [sdk/python/__init__.py](https://github.com/superradcompany/microsandbox/blob/main/sdk/python/__init__.py) |
MICROSANDBOX_LOG=debug python my_script.py |
| TypeScript | [sdk/node-ts/src/index.ts](https://github.com/superradcompany/microsandbox/blob/main/sdk/node-ts/src/index.ts) |
MICROSANDBOX_LOG=debug node my_script.js |
| Go | [sdk/go/sandbox.go](https://github.com/superradcompany/microsandbox/blob/main/sdk/go/sandbox.go) |
MICROSANDBOX_LOG=debug go run main.go or ms.WithLogLevel(ctx, "debug") |
Locate and Filter microsandbox Log Files
By default, logs write to ~/.microsandbox/logs/ as JSON-lines. The structure enables precise filtering with jq.
Log File Organization
~/.microsandbox/logs/
├── msb.json # CLI-level events
├── runtime.json # Runtime and agentd events
├── metrics.json # Metrics collector output
└── sandbox-<name>.json # Per-sandbox trace (when --trace enabled)
jq Filtering Examples
# All agentd messages from the runtime
jq 'select(.target == "agentd")' ~/.microsandbox/logs/runtime.json
# Network policy rejections
jq 'select(.fields.message | contains("policy::reject"))' ~/.microsandbox/logs/runtime.json
# Boot timing events
jq 'select(.span.name == "vm_boot")' ~/.microsandbox/logs/metrics.json
The JSON format includes standard tracing fields: timestamp, level, target, span, and custom fields with structured data.
Debug Common microsandbox Issues
Sandbox Fails to Start
- Enable CLI debug:
msb --log-level debug run … - Inspect
runtime.jsonforvm::bootspan events - Check for KVM/WHP/Apple Hypervisor availability errors
Look for these specific error patterns in [crates/runtime/lib/sandbox.rs](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/sandbox.rs):
"kvm": "permission denied on /dev/kvm"→ Add user tokvmgroup"whp": "Windows Hypervisor Platform not available"→ Enable in Windows Features"image_pull": "manifest not found"→ Verify image name and registry access
Network Requests Blocked
Network policy enforcement emits trace events from [crates/network/lib/policy.rs](https://github.com/superradcompany/microsandbox/blob/main/crates/network/lib/policy.rs).
# Find rejected connections
jq 'select(.fields | has("policy_action") and .policy_action == "reject")' \
~/.microsandbox/logs/runtime.json
Key fields to examine:
policy_rule– The rule that matched the requesthostandport– The destination that was deniedsandbox_id– Which sandbox initiated the request
File-System Mount Errors
Mount operations use the mount:: span namespace. Search for:
jq 'select(.target | contains("mount"))' ~/.microsandbox/logs/runtime.json
Common errors in the output:
"error": "cannot open source path"– Verify host path exists and is readable"error": "volume already in use"– Check for orphaned sandbox processes"error": "incompatible fs type"– Confirm the guest kernel supports the filesystem
Unexpected Process Termination
Process lifecycle logging resides in [crates/utils/lib/process.rs](https://github.com/superradcompany/microsandbox/blob/main/crates/utils/lib/process.rs). Correlate child_reaping events with sandbox::stop spans:
jq 'select(.span.name | test("(child_reaping|sandbox_stop)"))' \
~/.microsandbox/logs/runtime.json | jq -s 'sort_by(.timestamp)'
Look for signal numbers, exit codes, and core-dump indicators in the fields object.
Performance Debugging
The metrics collector (binary in [crates/metrics-collector/bin/main.rs](https://github.com/superradcompany/microsandbox/blob/main/crates/metrics-collector/bin/main.rs)) exports timing data:
# Boot time breakdown
jq 'select(.name == "boot_time_ms")' ~/.microsandbox/logs/metrics.json
# Image download vs VM init latency
jq 'select(.name | test("(image_pull|vm_init)"))' ~/.microsandbox/logs/metrics.json
Code Examples for microsandbox Debugging
Rust: Capturing SDK Errors with Context
From [sdk/rust/src/lib.rs](https://github.com/superradcompany/microsandbox/blob/main/sdk/rust/src/lib.rs), the Sandbox type exposes detailed error chains:
use microsandbox::Sandbox;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
std::env::set_var("RUST_LOG", "debug");
tracing_subscriber::fmt::init();
let sandbox = Sandbox::builder("demo")
.image("python")
.cpus(1)
.memory(512)
.create()
.await?;
// The {:#} format shows the full error chain with source locations
match sandbox.exec("python", ["-c", "raise Exception('boom')"]).await {
Ok(out) => println!("{}", out.stdout()?),
Err(e) => eprintln!("exec failed: {:#}", e),
}
sandbox.stop().await?;
Ok(())
}
The {:#} debug format on anyhow::Error includes spantraces when tracing-error is enabled.
Python: Debug-Ready Script
import os
import asyncio
from microsandbox import Sandbox, logger
async def main():
os.environ["MICROSANDBOX_LOG"] = "debug"
logger.setLevel("DEBUG") # Forwards to Python's logging module
sandbox = await Sandbox.create(
"py-demo",
image="python",
cpus=1,
memory=512,
)
try:
out = await sandbox.exec("python", ["-c", "print('hello')"])
print(out.stdout_text)
except Exception as e:
logger.exception("Sandbox execution failed")
raise
finally:
await sandbox.stop()
asyncio.run(main())
TypeScript: Enabling Per-Process Tracing
import { Sandbox } from "microsandbox";
process.env.MICROSANDBOX_LOG = "debug";
(async () => {
const sandbox = await Sandbox.builder("ts-demo")
.image("python")
.cpus(1)
.memory(512)
.create();
try {
const out = await sandbox.exec("python", ["-c", "print('hello')"]);
console.log(out.stdout());
} catch (e) {
console.error("Sandbox error:", e);
throw e;
} finally {
await sandbox.stop();
}
})();
Go: Context-Aware Log Levels
The Go SDK supports per-context log levels via ms.WithLogLevel:
package main
import (
"context"
"log"
ms "github.com/superradcompany/microsandbox/sdk/go"
)
func main() {
ctx := context.Background()
ctx = ms.WithLogLevel(ctx, "debug") // Sets MICROSANDBOX_LOG for subprocesses
sandbox, err := ms.CreateSandbox(ctx, "go-demo",
ms.WithImage("python"),
ms.WithCPUs(1),
ms.WithMemory(512),
)
if err != nil {
log.Fatalf("create sandbox: %v", err)
}
defer sandbox.Stop(ctx)
out, err := sandbox.Exec(ctx, "python", []string{"-c", "print('hi')"})
if err != nil {
log.Fatalf("exec: %v", err)
}
log.Printf("Output: %s", out.Stdout())
}
Key Source Files for microsandbox Debugging
Quick Debug Checklist for microsandbox
- Set debug log level:
RUST_LOG=debug,MICROSANDBOX_LOG=debug, ormsb --log-level debug - Reproduce the issue with logging enabled
- Locate JSON logs in
~/.microsandbox/logs/ - Filter with
jqusingselect(.target),select(.span.name), orselect(.level == "ERROR") - Correlate timestamps across
msb.json,runtime.json, andmetrics.json - Verify host hypervisor:
kvm-ok(Linux), Windows Features (WHP), System Info (macOS) - Cross-reference error events with source files above
- Include filtered log excerpts when reporting issues
Summary
- Three layers produce debug output: CLI (
msb), language SDKs, and runtime/agent — all using the structuredtracingsystem - Environment variables control verbosity:
RUST_LOGfor Rust,MICROSANDBOX_LOGfor all SDKs,--log-levelfor CLI - JSON-lines format in
~/.microsandbox/logs/enables precise filtering withjqby target, span, level, or message content - Common issues map to specific log patterns: VM boot failures, network
policy::reject, mount errors, and process termination signals - Source code reference grounds debugging in actual implementation: lifecycle in
sandbox.rs, policy inpolicy.rs, subscriber setup inmetrics-collector/bin/main.rs
Frequently Asked Questions
What is the difference between RUST_LOG and MICROSANDBOX_LOG?
RUST_LOG is the standard tracing crate environment variable, used primarily for Rust-native code and the metrics-collector binary. MICROSANDBOX_LOG is the cross-language variable that all SDKs (Python, TypeScript, Go) read to configure their underlying tracing integration. When using Rust, prefer RUST_LOG; for other languages or mixed environments, use MICROSANDBOX_LOG. Both accept the same level syntax: debug, microsandbox=trace, or target-specific filters like network=debug,runtime=info.
How do I debug a sandbox that crashes immediately on start?
Enable msb --log-level debug run … and inspect ~/.microsandbox/logs/runtime.json for spans named vm::boot or image_pull. Check for hypervisor availability errors (/dev/kvm permissions on Linux, WHP on Windows, Hypervisor.framework on macOS). The boot_time_ms metric in metrics.json helps distinguish between slow image pulls and VM initialization failures. Cross-reference any error messages with [crates/runtime/lib/sandbox.rs](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/sandbox.rs) for the exact failure path.
Can I redirect microsandbox logs to stdout instead of files?
The default subscriber in metrics-collector writes to rolling JSON files for structured analysis. For development, override the subscriber in your application code: tracing_subscriber::fmt::fmt().with_writer(std::io::stdout).init() in Rust, or set MICROSANDBOX_LOG_FORMAT=pretty if supported by your SDK version. The CLI flag --log-level also affects stderr verbosity in real-time, though full JSON traces always route to the log directory for persistence.
Why are my network requests being blocked inside the sandbox?
Network policy enforcement emits policy::reject events from [crates/network/lib/policy.rs](https://github.com/superradcompany/microsandbox/blob/main/crates/network/lib/policy.rs). Filter logs with jq 'select(.fields.policy_action == "reject")' to see the denied host, port, and matching rule. Default policies often block all outbound traffic; configure explicit allow rules in your sandbox configuration or use the network: open preset for debugging purposes only.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →