tutorial

How to Monitor Yew with Vigilmon

Add production-grade uptime monitoring and heartbeat checks to your Yew Rust/WebAssembly web application with Vigilmon — catch outages and silent failures before your users notice.

Yew is a modern Rust framework for building multi-threaded front-end web applications compiled to WebAssembly. It brings Rust's memory safety and performance guarantees to the browser, enabling component-based UIs with the power of a systems language. But Wasm-based UIs still depend on backend APIs, databases, and background services — and those can fail silently. Vigilmon provides continuous HTTP monitoring, heartbeat checks, and instant alerts so you know the moment something breaks — before your users do.

What You'll Build

  • A /health endpoint for your Yew backend API server
  • Vigilmon HTTP monitors for your app and API
  • A heartbeat monitor for background jobs
  • Alert channels (email and Slack)
  • An uptime badge rendered in your Yew component tree

Prerequisites

  • A Yew project with a backend API (Axum, Actix-web, or Rocket)
  • A free Vigilmon account

Step 1: Add a Health Endpoint

Your Yew WASM bundle is served as static assets, but your backend API server needs a health endpoint that Vigilmon can poll continuously. Here's an example with Axum:

// src/main.rs (backend with Axum)
use axum::{
    http::StatusCode,
    response::Json,
    routing::get,
    Router,
};
use serde_json::{json, Value};
use tower_http::services::ServeDir;

async fn health_handler() -> (StatusCode, Json<Value>) {
    let mut checks = serde_json::Map::new();
    let mut degraded = false;

    // Database connectivity check
    match check_database().await {
        Ok(_) => { checks.insert("database".into(), json!("ok")); }
        Err(e) => {
            checks.insert("database".into(), json!(format!("error: {}", e)));
            degraded = true;
        }
    }

    // Cache check (e.g. Redis)
    match check_cache().await {
        Ok(_) => { checks.insert("cache".into(), json!("ok")); }
        Err(e) => {
            checks.insert("cache".into(), json!(format!("error: {}", e)));
            degraded = true;
        }
    }

    let status_code = if degraded { StatusCode::SERVICE_UNAVAILABLE } else { StatusCode::OK };
    let body = json!({
        "status": if degraded { "degraded" } else { "ok" },
        "checks": checks,
    });

    (status_code, Json(body))
}

async fn check_database() -> Result<(), String> {
    // pool.acquire().await.map_err(|e| e.to_string())?;
    Ok(())
}

async fn check_cache() -> Result<(), String> {
    // redis_client.ping().await.map_err(|e| e.to_string())?;
    Ok(())
}

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/health", get(health_handler))
        // Serve your compiled Yew WASM app
        .nest_service("/", ServeDir::new("dist"));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

Test it locally:

curl http://localhost:3000/health | jq .
# {"status":"ok","checks":{"database":"ok","cache":"ok"}}

Step 2: Configure Vigilmon HTTP Monitors

Log in to VigilmonMonitors → New Monitor:

Monitor 1: Yew App (Frontend / WASM Bundle)

| Field | Value | |---|---| | URL | https://yourapp.com/ | | Method | GET | | Expected status | 200 | | Expected body | A stable string from your index.html shell | | Check interval | 1 minute |

Monitor 2: Health API

| Field | Value | |---|---| | URL | https://yourapp.com/health | | Method | GET | | Expected status | 200 | | Expected body | "status":"ok" | | Check interval | 1 minute |

Separating frontend from API monitoring is especially important for Yew apps: the static WASM bundle may be served from a CDN while the Axum backend runs on a separate host — failures are independent.


Step 3: Heartbeat for Background Tasks

Yew-powered apps often consume data from backend workers — data aggregation pipelines, WebSocket feed producers, or scheduled report generators. A Vigilmon heartbeat monitor detects when these workers stop silently:

// src/worker.rs
use std::time::Duration;
use tokio::time;

const VIGILMON_HEARTBEAT_URL: &str = env!("VIGILMON_HEARTBEAT_URL");

#[tokio::main]
async fn main() {
    let mut interval = time::interval(Duration::from_secs(300)); // 5 minutes

    loop {
        interval.tick().await;

        match process_data().await {
            Ok(_) => {
                // Only ping after successful processing
                if let Err(e) = ping_heartbeat().await {
                    eprintln!("[worker] Heartbeat ping failed: {}", e);
                }
            }
            Err(e) => {
                eprintln!("[worker] Processing failed: {} — skipping heartbeat ping", e);
                // No ping → Vigilmon alerts when the heartbeat window expires
            }
        }
    }
}

async fn process_data() -> Result<(), Box<dyn std::error::Error>> {
    // Your backend data processing logic here
    Ok(())
}

async fn ping_heartbeat() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    client
        .get(VIGILMON_HEARTBEAT_URL)
        .timeout(Duration::from_secs(5))
        .send()
        .await?;
    Ok(())
}

Set up the heartbeat in Vigilmon:

  1. Monitors → New Heartbeat Monitor
  2. Set Expected interval to 10 minutes (2× the worker interval)
  3. Add the ping URL to your build environment:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/xxxxxxxx

Step 4: Embed an Uptime Badge in Your Yew Component

Yew uses a JSX-like macro syntax (html!) for building component trees. You can include a Vigilmon status badge as a static leaf node:

// src/components/footer.rs
use yew::prelude::*;

const BADGE_URL: &str = "https://vigilmon.online/api/badge/your-monitor-id.svg";
const STATUS_URL: &str = "https://vigilmon.online/status/your-monitor-slug";

#[function_component(Footer)]
pub fn footer() -> Html {
    html! {
        <footer class="footer">
            <a
                href={STATUS_URL}
                target="_blank"
                rel="noopener noreferrer"
                aria-label="Service uptime status"
            >
                <img
                    src={BADGE_URL}
                    alt="Uptime"
                    width="120"
                    height="20"
                />
            </a>
        </footer>
    }
}

// src/app.rs
use yew::prelude::*;
use crate::components::footer::Footer;

#[function_component(App)]
pub fn app() -> Html {
    html! {
        <div class="app">
            <main>
                <p>{ "Your content here." }</p>
            </main>
            <Footer />
        </div>
    }
}

Yew's virtual DOM only re-renders components when their props or hooks change — the static Footer component with no props is never re-rendered during data updates, so the badge image is never refetched.


Step 5: Set Up Alert Channels

In Vigilmon's Alert Channels settings:

Email Alerts

  1. Alert Channels → Email → add your on-call address
  2. Attach the channel to both HTTP monitors and the heartbeat monitor

Slack Alerts

  1. Create a Slack Incoming Webhook for your #alerts channel
  2. Alert Channels → Webhook → paste the Slack webhook URL
  3. Use this payload template:
{
  "text": "🚨 *{{ monitor.name }}* is DOWN\n{{ monitor.url }}\nStatus: {{ event.status }}\n<https://vigilmon.online|Open Vigilmon>"
}

Step 6: Verify Everything Works

# 1. Confirm health endpoint returns 200
curl -s https://yourapp.com/health | jq .status

# 2. Simulate a failure — break your DB connection string and redeploy
# Expected: health endpoint returns 503; Vigilmon alerts within ~2 minutes

# 3. Remove the heartbeat URL env var and let the worker run one cycle
# Expected: heartbeat alert fires after the grace window expires

# 4. In Vigilmon → "Test Alert" to confirm Slack/email delivery

Summary

| Monitor | What It Catches | |---|---| | HTTP app check | CDN failures, WASM bundle serving issues | | HTTP health API | Database, cache, and backend dependency failures | | Heartbeat | Worker crashes, silent data pipeline failures |


Next Steps

  • Create separate Vigilmon projects for staging and production
  • Use Vigilmon's response time graphs to correlate backend API latency with Yew component re-render frequency
  • Configure escalating alerts: email for recoveries, Slack for active outages, PagerDuty for SLA-critical monitors

Ready to get started? Sign up for Vigilmon free — have your first monitor running in under 5 minutes.

Monitor your app with Vigilmon

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

Start free →