tutorial

Monitoring Extism with Vigilmon

Extism is the universal WebAssembly plugin system — but plugin call latency spikes, host function availability gaps, memory allocation failures, and cross-language compatibility regressions silently break your plugin-driven workloads. Here's how to monitor Extism plugin health, call latency, memory usage, and host function availability with Vigilmon.

Extism is the Bytecode Alliance-ecosystem WebAssembly plugin system that lets you embed user-defined plugins in any host language — Rust, Go, Python, Node.js, Ruby, and more — using a unified SDK. Your host application loads .wasm plugin files at runtime, calls plugin exports, and the plugin calls back through host functions your application exposes. When plugin call latency climbs because a newly deployed .wasm binary is doing excessive allocations, when a host function you removed without updating plugin contracts causes silent null returns, when memory grows unbounded across repeated plugin invocations in a long-lived host, or when cross-language PDK (Plugin Development Kit) version mismatches cause marshalling failures, your plugin-driven features degrade invisibly. The host stays up, requests return, but the data coming back is wrong or incomplete. Vigilmon gives you external monitoring for Extism host process health, plugin call latency, host function availability, memory allocation patterns, and cross-language compatibility so you catch plugin runtime problems before they surface as application bugs.

What You'll Set Up

  • Extism host process health via cron heartbeats
  • Plugin call latency tracking
  • Host function availability monitoring
  • Memory allocation health across plugin invocations
  • Cross-language plugin compatibility checks

Prerequisites

  • Extism 1.0+ SDK embedded in a host application (Rust, Go, Node.js, Python, or other)
  • Access to your host application's logs or a metrics endpoint
  • A free Vigilmon account

Step 1: Monitor the Extism Host Process Health

Extism plugins run inside a host process. When the host crashes — due to OOM from a runaway plugin, a panic in host function code, or a WASM trap that bubbles up through the Extism runtime — all in-flight plugin calls are lost. Start by monitoring the host process liveness with a cron heartbeat:

  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/extism-host-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/abc123"
HOST_PROCESS_NAME="my-plugin-host"   # Replace with your host binary name

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

Install the cron job:

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

If your host exposes an HTTP health endpoint (common in web service hosts), add an HTTP monitor in Vigilmon pointing to it:

  1. Click Add MonitorHTTP / HTTPS.
  2. Enter your health URL: https://your-plugin-host.example.com/health.
  3. Set check interval to 1 minute and alert after 2 failures.

This gives you sub-minute detection for host-level outages, much faster than the 2-minute heartbeat window.


Step 2: Track Plugin Call Latency

Extism plugin calls involve WASM module instantiation or cache lookup, input serialization into WASM linear memory, the plugin function execution, and output deserialization back to the host. Any of these steps can introduce latency — a plugin doing large JSON parsing, a host that isn't caching plugin instances, or a WASM module compiled without optimization flags. Build a latency probe that calls a known-fast plugin function and measures round-trip time:

#!/bin/bash
# /usr/local/bin/extism-latency-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/def456"
PLUGIN_ENDPOINT="http://localhost:8080/plugin/health-check"
LATENCY_THRESHOLD_MS=200

START_MS=$(date +%s%3N)
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  -X POST "$PLUGIN_ENDPOINT" \
  -H "Content-Type: application/json" \
  -d '{"input": "ping"}' \
  --max-time 5)
END_MS=$(date +%s%3N)

LATENCY_MS=$((END_MS - START_MS))

if [ "$HTTP_CODE" != "200" ]; then
  echo "Plugin call failed: HTTP $HTTP_CODE"
  exit 1
fi

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

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

Schedule this check every 5 minutes. A sudden jump in plugin call latency often indicates:

  • A newly deployed plugin binary that wasn't compiled with wasm-opt optimizations
  • Plugin instance cache eviction forcing repeated cold-start compilation overhead
  • A host function call inside the plugin that is making external network requests
  • Growing input payloads that are hitting quadratic serialization paths

The 200ms threshold is a reasonable starting point for a warmed plugin cache. For cold-start latency (first call after process restart), expect 50–500ms more depending on module size.


Step 3: Monitor Host Function Availability

Extism host functions are Go, Rust, Python, or other host-language functions that plugins call back into during execution. They're registered at host startup and form a contract that all loaded plugins depend on. If you refactor a host function (rename it, change its signature, remove it), plugins compiled against the old contract will fail at call time — often with silent null returns rather than visible errors, because Extism's WASM host function resolution fails gracefully in some PDK versions.

Write a host function availability check that loads a canary plugin and exercises the host functions it uses:

#!/bin/bash
# /usr/local/bin/extism-hostfn-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/ghi789"
CANARY_ENDPOINT="http://localhost:8080/plugin/canary"

# The canary plugin calls all registered host functions and returns a status JSON
RESPONSE=$(curl -s -X POST "$CANARY_ENDPOINT" \
  -H "Content-Type: application/json" \
  -d '{"check": "host_functions"}' \
  --max-time 10)

if [ -z "$RESPONSE" ]; then
  echo "No response from canary endpoint"
  exit 1
fi

# Check that all expected host functions returned non-null
FAILED=$(echo "$RESPONSE" | python3 -c "
import sys, json
data = json.load(sys.stdin)
failed = [k for k, v in data.get('host_functions', {}).items() if not v]
print(','.join(failed))
" 2>/dev/null)

if [ -n "$FAILED" ]; then
  echo "Host functions unavailable: $FAILED"
  exit 1
fi

echo "All host functions available"
curl -s "$HEARTBEAT_URL"

The canary plugin itself should be a minimal .wasm file maintained in your test suite that calls each host function with a known input and records whether it got a valid response. Deploy updates to the canary plugin alongside your host function contract changes to catch mismatches in CI before they reach production.

Create this as a Vigilmon heartbeat with a 10-minute expected interval. Host function availability doesn't change frequently, so a 10-minute check gives a good balance of coverage and overhead.


Step 4: Track Memory Allocation Health

Extism allocates WASM linear memory for each plugin invocation to pass input and output data between the host and the plugin. For plugins that process large payloads — document parsing, image manipulation, large JSON trees — each call temporarily allocates significant memory in the plugin's WASM address space. In a long-lived host with high call rates, if the plugin isn't correctly freeing its output buffers (a common PDK bug), memory grows without bound across invocations.

Monitor the host process RSS as a proxy for plugin memory health:

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

HEARTBEAT_URL="https://vigilmon.online/heartbeat/jkl012"
HOST_PROCESS_NAME="my-plugin-host"
MAX_MEMORY_MB=1024
MEMORY_GROWTH_THRESHOLD_MB=50   # Alert if RSS grew > 50MB since last check

STATE_FILE="/tmp/extism-memory-state"
PID=$(pgrep -x "$HOST_PROCESS_NAME" | head -1)

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

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

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

# Check growth rate against last reading
if [ -f "$STATE_FILE" ]; then
  PREV_MB=$(cat "$STATE_FILE")
  GROWTH_MB=$((RSS_MB - PREV_MB))
  if [ "$GROWTH_MB" -gt "$MEMORY_GROWTH_THRESHOLD_MB" ]; then
    echo "Memory growing fast: +${GROWTH_MB}MB since last check (now ${RSS_MB}MB)"
    exit 1
  fi
fi

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

Run this check every 5 minutes. The growth rate check (MEMORY_GROWTH_THRESHOLD_MB) is particularly useful: a plugin with a memory leak shows a steady upward trend that the absolute threshold won't catch until it's too late, but the growth rate check fires early.

If your Extism host exposes Prometheus metrics, add a Vigilmon HTTP monitor:

  1. Click Add MonitorHTTP / HTTPS.
  2. Enter http://your-plugin-host:9090/metrics.
  3. Add a Keyword check for extism_memory_bytes.

Step 5: Verify Cross-Language Plugin Compatibility

Extism's PDK (Plugin Development Kit) exists for Rust, Go, AssemblyScript, C/C++, Python, TypeScript, and others. Each PDK version serializes and deserializes input/output data in a specific way. When you upgrade the Extism host SDK without also recompiling plugins against a compatible PDK version, you get silent data corruption: the plugin runs, the host gets a response, but the payload is garbled because the memory layout conventions changed. Detect this with a round-trip serialization check:

#!/bin/bash
# /usr/local/bin/extism-compat-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/mno345"

# Test a known input → known output round-trip for each plugin language
declare -A PLUGINS=(
  ["rust"]="http://localhost:8080/plugin/rust-echo"
  ["go"]="http://localhost:8080/plugin/go-echo"
  ["typescript"]="http://localhost:8080/plugin/ts-echo"
)

EXPECTED_OUTPUT="hello-extism-compat-check"
ALL_OK=true

for LANG in "${!PLUGINS[@]}"; do
  ENDPOINT="${PLUGINS[$LANG]}"
  RESPONSE=$(curl -s -X POST "$ENDPOINT" \
    -H "Content-Type: text/plain" \
    -d "$EXPECTED_OUTPUT" \
    --max-time 5)

  if [ "$RESPONSE" != "$EXPECTED_OUTPUT" ]; then
    echo "Compatibility check failed for $LANG plugin: got '$RESPONSE', expected '$EXPECTED_OUTPUT'"
    ALL_OK=false
  else
    echo "$LANG plugin: OK"
  fi
done

if [ "$ALL_OK" = false ]; then
  exit 1
fi

curl -s "$HEARTBEAT_URL"

The key insight is that the echo function — which takes an input string and returns it unchanged — is the simplest possible PDK contract. If the echo round-trip breaks, the PDK serialization layer is incompatible. Run this check every 15 minutes to catch SDK upgrade regressions before they affect real workloads.

For additional safety, add a Vigilmon keyword monitor on your plugin host's version endpoint:

  1. Click Add MonitorHTTP / HTTPS.
  2. Enter http://your-plugin-host.example.com/version.
  3. Add a Keyword check for your expected Extism SDK version string (e.g., extism/1.4).

This confirms that the correct SDK version is running in production and catches accidental downgrades during rollbacks.


Putting It All Together

With these five monitors in place, your Vigilmon dashboard gives you full Extism observability:

| Monitor | Type | Check Interval | Alert On | |---------|------|----------------|----------| | Host process health | Cron heartbeat | 2 min | Missing ping | | Plugin call latency | Cron heartbeat | 5 min | Latency > 200ms | | Host function availability | Cron heartbeat | 10 min | Any function unavailable | | Memory allocation health | Cron heartbeat | 5 min | RSS > 1 GB or growth > 50 MB | | Cross-language compatibility | Cron heartbeat | 15 min | Echo round-trip mismatch |

The highest-priority alert is host process health — a crashed host is a complete outage. The second priority is host function availability, because silent host function failures produce wrong results rather than visible errors, making them the hardest bugs to notice without dedicated monitoring.

Extism's plugin isolation model means a crashing plugin won't crash the host, but it will silently return empty output. External monitoring with Vigilmon catches the patterns that Extism's WASM sandbox doesn't expose: growing memory trends, host function contract drift, and PDK version mismatches that all manifest as subtle data corruption rather than obvious failures.

Sign up for a free Vigilmon account and add your first Extism 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 →