tutorial

Monitoring Wasmtime with Vigilmon

Wasmtime is the Bytecode Alliance's production-grade WASM runtime — but module instantiation latency spikes, memory leaks across instances, fuel exhaustion halts, and elevated trap rates silently degrade your WebAssembly workloads. Here's how to monitor Wasmtime health, instance memory, fuel consumption, and trap rates with Vigilmon.

Wasmtime is the Bytecode Alliance's production-grade WebAssembly runtime, widely used for server-side WASM execution, plugin systems, and sandboxed compute workloads. It runs compiled .wasm modules in isolated sandboxes with configurable CPU fuel limits, linear memory caps, and a full WASI interface. When module instantiation latency climbs due to JIT compilation overhead, when instance memory grows unbounded across a long-lived host process, when fuel limits are hit unexpectedly causing silent computation halts, or when trap rates spike from malformed or buggy modules, your WASM workloads degrade invisibly — the host process stays up, but the modules inside are failing. Vigilmon gives you external monitoring for Wasmtime process health, module instantiation performance, per-instance memory usage, fuel consumption patterns, and trap/error rates so you catch WASM runtime problems before they impact your application.

What You'll Set Up

  • Wasmtime host process health via cron heartbeats
  • Module instantiation latency tracking
  • Per-instance memory usage monitoring
  • Fuel consumption and exhaustion alerting
  • Trap and error rate monitoring

Prerequisites

  • Wasmtime 14+ embedded in a host application or running standalone via the wasmtime CLI
  • Wasmtime's built-in metrics or a metrics export script reading /proc / host APIs
  • A free Vigilmon account

Step 1: Monitor Wasmtime Host Process Health

Wasmtime typically runs embedded in a host process — a Rust binary, a Node.js addon, a Go application, or a custom runtime. When the host process crashes or is OOM-killed, all running WASM instances are lost with no graceful shutdown. Start by monitoring process liveness:

  1. In Vigilmon, click Add MonitorCron Heartbeat.
  2. Set Expected ping interval to 2 minutes.
  3. Copy the heartbeat URL (e.g., https://vigilmon.online/heartbeat/abc123).

Create the health check script:

#!/bin/bash
# /usr/local/bin/wasmtime-host-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/abc123"
HOST_PROCESS_NAME="my-wasm-host"   # Name of your Wasmtime host binary

if pgrep -x "$HOST_PROCESS_NAME" > /dev/null; then
  echo "Wasmtime host running"
  curl -s "$HEARTBEAT_URL"
elif systemctl is-active --quiet wasmtime-host 2>/dev/null; then
  echo "Wasmtime host active via systemd"
  curl -s "$HEARTBEAT_URL"
else
  echo "Wasmtime host not running"
  exit 1
fi

Install the cron job:

chmod +x /usr/local/bin/wasmtime-host-check.sh
(crontab -l 2>/dev/null; echo "*/2 * * * * /usr/local/bin/wasmtime-host-check.sh >> /var/log/wasmtime-health.log 2>&1") | crontab -

If your host exposes an HTTP management endpoint or health route, add an HTTP monitor in Vigilmon pointing to it for faster liveness detection than a 2-minute heartbeat gap.


Step 2: Track Module Instantiation Latency

Wasmtime compiles .wasm modules on first instantiation (unless pre-compiled to .cwasm). On large modules, JIT compilation can take hundreds of milliseconds or more. In production environments that instantiate modules per-request (e.g., plugin systems, FaaS-style architectures), high instantiation latency directly adds to tail latency. Build a latency probe:

#!/bin/bash
# /usr/local/bin/wasmtime-instantiation-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/def456"
WASM_MODULE="/opt/wasm-modules/health-check.wasm"
LATENCY_THRESHOLD_MS=500   # Alert if instantiation > 500ms

# Time the instantiation
START_MS=$(date +%s%3N)
wasmtime run --allow-precompiled "$WASM_MODULE" > /dev/null 2>&1
EXIT_CODE=$?
END_MS=$(date +%s%3N)

LATENCY_MS=$((END_MS - START_MS))

if [ $EXIT_CODE -ne 0 ]; then
  echo "WASM module failed to run (exit $EXIT_CODE)"
  exit 1
fi

if [ $LATENCY_MS -gt $LATENCY_THRESHOLD_MS ]; then
  echo "Instantiation latency too high: ${LATENCY_MS}ms > threshold ${LATENCY_THRESHOLD_MS}ms"
  exit 1
fi

echo "Instantiation OK: ${LATENCY_MS}ms"
curl -s "$HEARTBEAT_URL"

For pre-warmed module caches (using wasmtime compile to generate .cwasm files), latency should be under 20ms. If you're seeing latencies over 100ms on pre-compiled modules, it usually signals CPU pressure or memory pressure causing compilation cache misses — both worth alerting on.

Create a dedicated heartbeat monitor for this script with a 5-minute expected interval. If instantiation starts failing or taking too long, the heartbeat stops and Vigilmon alerts your team.


Step 3: Monitor Per-Instance Memory Usage

Wasmtime instances have configurable linear memory limits (set via wasmtime::MemoryType or --max-wasm-stack / --fuel CLI flags). A module that continuously grows its linear memory without releasing it can exhaust the host process's address space over time. Monitor the host process's total memory footprint as a proxy:

#!/bin/bash
# /usr/local/bin/wasmtime-memory-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/ghi789"
HOST_PROCESS_NAME="my-wasm-host"
MAX_MEMORY_MB=2048   # Alert if host RSS > 2 GB

PID=$(pgrep -x "$HOST_PROCESS_NAME" | head -1)

if [ -z "$PID" ]; then
  echo "Host process not found"
  exit 1
fi

# Read RSS from /proc (in KB), convert to MB
RSS_KB=$(awk '/VmRSS/ {print $2}' "/proc/$PID/status" 2>/dev/null)
RSS_MB=$((RSS_KB / 1024))

if [ -z "$RSS_KB" ]; then
  echo "Could not read memory for PID $PID"
  exit 1
fi

if [ $RSS_MB -gt $MAX_MEMORY_MB ]; then
  echo "Host memory too high: ${RSS_MB}MB > threshold ${MAX_MEMORY_MB}MB"
  exit 1
fi

echo "Memory OK: ${RSS_MB}MB RSS"
curl -s "$HEARTBEAT_URL"

If your Wasmtime host exposes a Prometheus metrics endpoint (common in Rust hosts using the metrics crate), add an HTTP monitor in Vigilmon pointing to it and use a keyword check to verify that wasm_instance_memory_bytes stays below your threshold.

For multi-instance hosts where you track per-instance memory, write the aggregate to a status file and check it:

# Example: host writes JSON status to /tmp/wasmtime-status.json
# {"active_instances": 42, "total_memory_mb": 1024, "max_instance_memory_mb": 256}

STATUS=$(cat /tmp/wasmtime-status.json 2>/dev/null)
TOTAL_MB=$(echo "$STATUS" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('total_memory_mb', 9999))")

if [ "$TOTAL_MB" -gt 1800 ]; then
  echo "Aggregate instance memory too high: ${TOTAL_MB}MB"
  exit 1
fi

Step 4: Alert on Fuel Consumption and Exhaustion

Wasmtime's fuel metering lets you cap the number of WASM instructions a module can execute, preventing infinite loops and runaway computation. When a module exhausts its fuel allocation, Wasmtime traps with wasm trap: all fuel consumed. In production, this is a silent failure mode — the caller gets an error, but nothing in your infrastructure signals that modules are consistently hitting fuel limits. Instrument your host to track fuel consumption:

// In your Rust Wasmtime host — track fuel metrics per invocation
use wasmtime::*;

fn invoke_module_with_metrics(
    engine: &Engine,
    module: &Module,
    fuel: u64,
    metrics_file: &str,
) -> anyhow::Result<()> {
    let mut store = Store::new(engine, ());
    store.add_fuel(fuel)?;

    let instance = Instance::new(&mut store, module, &[])?;
    let func = instance.get_typed_func::<(), ()>(&mut store, "run")?;

    match func.call(&mut store, ()) {
        Ok(_) => {
            let remaining = store.fuel_consumed().unwrap_or(0);
            let consumed = fuel - (fuel - remaining).min(fuel);
            // Write metrics for monitoring
            std::fs::write(
                metrics_file,
                format!("fuel_consumed={}\nfuel_exhausted=0\n", consumed),
            )?;
        }
        Err(e) if e.to_string().contains("all fuel consumed") => {
            std::fs::write(
                metrics_file,
                format!("fuel_consumed={}\nfuel_exhausted=1\n", fuel),
            )?;
            return Err(e);
        }
        Err(e) => return Err(e),
    }
    Ok(())
}

Then monitor the metrics file with a shell script:

#!/bin/bash
# /usr/local/bin/wasmtime-fuel-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/jkl012"
METRICS_FILE="/tmp/wasmtime-metrics.txt"
MAX_EXHAUSTION_RATE=5   # Alert if > 5 exhaustions in last check cycle

EXHAUSTED=$(grep "fuel_exhausted=1" "$METRICS_FILE" 2>/dev/null | wc -l)

if [ "$EXHAUSTED" -gt "$MAX_EXHAUSTION_RATE" ]; then
  echo "Fuel exhaustion rate too high: $EXHAUSTED events"
  exit 1
fi

echo "Fuel OK: $EXHAUSTED exhaustions"
curl -s "$HEARTBEAT_URL"

Set the heartbeat interval to 5 minutes and alert threshold to 2 missed pings. A sudden spike in fuel exhaustions indicates a new module version with performance regressions or an adversarial workload attempting to monopolize compute.


Step 5: Monitor Trap and Error Rates

Wasmtime traps occur when a WASM module executes an invalid instruction — out-of-bounds memory access, integer divide-by-zero, unreachable opcode, or stack overflow. In a well-tested production module, traps should be near zero. A rising trap rate signals buggy modules, unexpected input shapes, or stack depth violations in recursive algorithms. Log and monitor trap events:

#!/bin/bash
# /usr/local/bin/wasmtime-trap-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/mno345"
WASMTIME_LOG="/var/log/wasmtime-host.log"
WINDOW_MINUTES=10
MAX_TRAPS=3   # Alert if > 3 traps in last 10 minutes

# Count trap events in recent log window
TRAP_COUNT=$(grep "wasm trap" "$WASMTIME_LOG" 2>/dev/null | \
  awk -v cutoff="$(date -d "-${WINDOW_MINUTES} minutes" '+%Y-%m-%dT%H:%M')" \
  '$0 >= cutoff' | wc -l)

if [ "$TRAP_COUNT" -gt "$MAX_TRAPS" ]; then
  echo "Trap rate too high: $TRAP_COUNT traps in last ${WINDOW_MINUTES}m"
  exit 1
fi

echo "Trap rate OK: $TRAP_COUNT traps in last ${WINDOW_MINUTES}m"
curl -s "$HEARTBEAT_URL"

If your host uses structured logging (e.g., JSON lines), parse the trap type as well to distinguish stack overflows from memory access violations — they have different root causes and different remediation paths.

For HTTP-accessible hosts that expose trap metrics via /metrics or a status endpoint, add a Vigilmon keyword monitor:

  1. In Vigilmon, click Add MonitorHTTP / HTTPS.
  2. Enter your metrics URL: https://your-wasm-host.internal/metrics.
  3. Set Keyword to wasm_traps_total.
  4. Under Advanced, use a response body check to confirm the count stays below your threshold.

Putting It All Together

With these five monitors in place, your Vigilmon dashboard gives you complete Wasmtime visibility:

| Monitor | Type | Check Interval | Alert On | |---------|------|----------------|----------| | Host process health | Cron heartbeat | 2 min | Missing ping | | Module instantiation latency | Cron heartbeat | 5 min | Latency > 500ms | | Instance memory usage | Cron heartbeat | 5 min | RSS > 2 GB | | Fuel exhaustion rate | Cron heartbeat | 5 min | > 5 exhaustions | | Trap rate | Cron heartbeat | 10 min | > 3 traps/window |

The most impactful alert to set up first is host process health — a crashed Wasmtime host is a total outage. Follow it with instantiation latency, which is the primary user-visible performance signal for request-scoped WASM architectures.

Wasmtime's sandboxing model means that a misbehaving module can't crash the host, but it can degrade performance and consume resources. External monitoring with Vigilmon catches the patterns that Wasmtime's internal isolation model doesn't expose: rising memory trends, fuel exhaustion spikes, and trap rate increases that all signal problems before they become outages.

Sign up for a free Vigilmon account and add your first Wasmtime heartbeat monitor in under two minutes.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →