tutorial

Analog.js Application Monitoring with Vigilmon

Analog.js is the full-stack Angular meta-framework — it brings file-based routing, server-side rendering, and API routes to Angular, much like Next.js does f...

Analog.js is the full-stack Angular meta-framework — it brings file-based routing, server-side rendering, and API routes to Angular, much like Next.js does for React. When you run Analog in production, you get a Node.js server you need to monitor.

This tutorial walks through adding uptime monitoring to an Analog.js application using Vigilmon. We will cover:

  • A typed health API route in Analog
  • HTTP monitoring in Vigilmon with keyword assertion
  • Webhook alerting on DOWN/UP transitions

Prerequisites

  • Node.js 18+
  • An Analog.js project (npm create analog@latest)
  • A free account at vigilmon.online

Part 1: Add a health API route

Analog uses Nitro under the hood for its server, so API routes live in src/server/routes/ and are plain TypeScript files.

Create src/server/routes/health.get.ts:

// src/server/routes/health.get.ts
import { defineEventHandler, setResponseStatus } from 'h3';

interface HealthCheck {
  name: string;
  status: 'ok' | 'error';
  message?: string;
}

interface HealthResponse {
  status: 'ok' | 'degraded';
  timestamp: string;
  uptime: number;
  checks: HealthCheck[];
}

export default defineEventHandler(async (event) => {
  const checks: HealthCheck[] = [];
  let degraded = false;

  // Example: check an environment variable is present (replace with real DB ping)
  if (process.env['DATABASE_URL']) {
    checks.push({ name: 'database_config', status: 'ok' });
  } else {
    checks.push({ name: 'database_config', status: 'error', message: 'DATABASE_URL not set' });
    degraded = true;
  }

  const status: HealthResponse['status'] = degraded ? 'degraded' : 'ok';
  const httpStatus = degraded ? 503 : 200;

  setResponseStatus(event, httpStatus);

  return {
    status,
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    checks,
  } satisfies HealthResponse;
});

The filename convention health.get.ts makes Analog/Nitro expose this handler at GET /api/health. Verify locally:

npm run dev
curl http://localhost:5173/api/health

Expected output:

{
  "status": "ok",
  "timestamp": "2026-06-30T10:00:00.000Z",
  "uptime": 12.3,
  "checks": [
    { "name": "database_config", "status": "ok" }
  ]
}

If any check fails, the route returns HTTP 503 — which Vigilmon treats as an outage.

Skipping Angular's SSR middleware for the health route

Analog runs Angular SSR on the server. Make sure your health route is resolved by Nitro before Angular's catch-all SSR handler. Because Analog places API routes under /api/ and Angular handles everything else, this works automatically without additional configuration.


Part 2: Set up HTTP monitoring in Vigilmon

  1. Log in to vigilmon.online and click Add Monitor.
  2. Choose HTTP(S) monitor.
  3. URL: https://yourapp.example.com/api/health
  4. Interval: 1 minute.
  5. Under Keyword assertion, enter "status":"ok" — Vigilmon will fail the check if this string is absent from the response body, even if the HTTP status is 200.
  6. Add your alert channel (email, Slack, or webhook URL).
  7. Click Save.

The keyword check catches the "degraded" case where your server responds 200 but an internal dependency has failed — a common pattern when load balancers absorb the HTTP status but pass through the application body.


Part 3: Receive Vigilmon webhooks

Add a webhook handler to fan out DOWN/UP alerts to Slack or your on-call system.

Create src/server/routes/webhook/vigilmon.post.ts:

// src/server/routes/webhook/vigilmon.post.ts
import { defineEventHandler, readBody } from 'h3';

interface VigilmonPayload {
  monitor_name: string;
  status: 'down' | 'up';
  url: string;
  response_code: number;
  checked_at: string;
}

export default defineEventHandler(async (event) => {
  const body = await readBody<VigilmonPayload>(event);

  if (body.status === 'down') {
    console.error('[VIGILMON] Monitor DOWN', {
      monitor: body.monitor_name,
      url: body.url,
      code: body.response_code,
      at: body.checked_at,
    });

    const slackUrl = process.env['SLACK_WEBHOOK_URL'];
    if (slackUrl) {
      await fetch(slackUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          text: `*ALERT*: ${body.monitor_name} is DOWN\nURL: ${body.url}\nCode: ${body.response_code}`,
        }),
      });
    }
  } else {
    console.info('[VIGILMON] Monitor recovered', { monitor: body.monitor_name });
  }

  return { received: true };
});

In Vigilmon, add a Webhook alert channel pointing at https://yourapp.example.com/api/webhook/vigilmon.


Part 4: Heartbeat monitoring for background tasks

If your Analog application runs background jobs (cron tasks via a separate worker, queues), use a Vigilmon heartbeat monitor so silence itself triggers an alert.

  1. In Vigilmon, click Add MonitorHeartbeat.
  2. Set expected interval to match your task frequency (e.g., 10 minutes).
  3. Copy the heartbeat URL: https://vigilmon.online/heartbeat/your-unique-token

Ping it at the end of each successful task run:

// src/server/utils/heartbeat.ts
export async function pingHeartbeat(): Promise<void> {
  const url = process.env['VIGILMON_HEARTBEAT_URL'];
  if (!url) return;
  try {
    await fetch(url, { signal: AbortSignal.timeout(5_000) });
  } catch (err) {
    console.warn('Heartbeat ping failed:', err);
  }
}
// In your background task / Nitro scheduled task
import { pingHeartbeat } from '../utils/heartbeat';

export default defineNitroPlugin((nitroApp) => {
  // Run a task every 10 minutes
  setInterval(async () => {
    try {
      await runMyBackgroundTask();
      await pingHeartbeat();
    } catch (err) {
      console.error('Background task failed:', err);
      // No heartbeat ping — Vigilmon alerts after the expected interval passes
    }
  }, 10 * 60 * 1000);
});

Deployment checklist

  • Set DATABASE_URL and other env vars in your hosting environment.
  • Set VIGILMON_HEARTBEAT_URL if you use heartbeat monitoring.
  • Optionally set SLACK_WEBHOOK_URL for the webhook handler.
  • Confirm GET /api/health is publicly reachable (not behind auth middleware).
  • Verify Vigilmon shows UP within two check intervals after deployment.

Summary

| What to monitor | How | |---|---| | App server availability | HTTP monitor on /api/health | | Internal dependency health | Keyword assertion on "status":"ok" | | Background task execution | Heartbeat monitor with pingHeartbeat() | | Alerts to your team | Webhook or Slack alert channel |

Analog.js gives you a clean TypeScript-first server layer — pairing it with Vigilmon adds the external monitoring layer that tells you what your users experience, not just what your logs say.

Monitor your app with Vigilmon

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

Start free →