tutorial

How to Monitor Hono with Vigilmon

Production monitoring for Hono apps on Cloudflare Workers, Bun, Deno, and Node.js — health endpoints, uptime checks, latency alerts, and Slack notifications.

How to Monitor Hono with Vigilmon

Hono is fast by design — sub-millisecond routing, tiny bundle, runs everywhere. But "everywhere" is also the challenge: Cloudflare Workers, Bun, Deno, AWS Lambda, Node.js all have different failure modes, cold start behaviors, and observability surfaces.

This tutorial shows you how to make a Hono application fully observable regardless of where it runs. By the end you'll have:

  • A /health endpoint that works on any Hono runtime
  • HTTP uptime monitoring with Vigilmon
  • Latency alerting with a response-body canary
  • Heartbeat monitoring for Hono scheduled Workers
  • Slack alerts for outages and recoveries

Why Monitor Hono Applications

Hono's minimal footprint means fewer moving parts — but the platform underneath can still fail:

  • Cloudflare Workers — CPU time limits (10ms–50ms), memory limits, subrequest limits; silent 1101 or 1042 errors from Cloudflare's edge
  • Bun runtime — process crash on uncaught promise rejection, port bind failure on restart
  • Deno Deploy — region-specific rollout failures; cold starts on low-traffic routes
  • AWS Lambda — function throttle, timeout (default 3s), cold start latency spikes
  • Node.js — OOM crashes, SIGKILL on container restart, uncaught exceptions

Hono surfaces all of these as HTTP errors or timeouts. A monitoring tool that pings your endpoint from multiple regions will catch every one of them.


Key Metrics to Watch

| Metric | What it means | |--------|---------------| | HTTP status of /health | App process is alive and responding | | Response time p50/p95 | Cold starts, upstream latency, CPU pressure | | Error rate on key routes | Unhandled exceptions reaching users | | Scheduled Worker execution | Cron triggers fired, job completed successfully | | KV / D1 / R2 reachability | Storage dependencies healthy |


Step 1: Add a Health Endpoint

Hono's API is runtime-agnostic, so the health route looks identical whether you deploy to Cloudflare Workers, Bun, or Node.js:

// src/routes/health.ts
import { Hono } from 'hono';

const health = new Hono();

health.get('/', (c) => {
  return c.json({
    status: 'ok',
    runtime: c.env?.CF_WORKER_ENV ?? process.env.NODE_ENV ?? 'unknown',
    timestamp: new Date().toISOString(),
  });
});

export { health };

Mount it in your main app:

// src/index.ts
import { Hono } from 'hono';
import { health } from './routes/health';

const app = new Hono();

app.route('/health', health);

export default app;

Adding a Dependency Check

If your Hono app reads from Cloudflare KV, D1, or an external API, check those too:

// src/routes/health.ts — Cloudflare Workers with D1 and KV
import { Hono } from 'hono';

type Bindings = {
  DB: D1Database;
  KV: KVNamespace;
};

const health = new Hono<{ Bindings: Bindings }>();

health.get('/', async (c) => {
  const checks: Record<string, 'ok' | 'error'> = {};
  let allOk = true;

  // D1 check
  try {
    await c.env.DB.prepare('SELECT 1').run();
    checks.d1 = 'ok';
  } catch {
    checks.d1 = 'error';
    allOk = false;
  }

  // KV check
  try {
    await c.env.KV.get('__health_probe__');
    checks.kv = 'ok';
  } catch {
    checks.kv = 'error';
    allOk = false;
  }

  return c.json({ status: allOk ? 'ok' : 'degraded', checks }, allOk ? 200 : 503);
});

export { health };

Test locally:

# Bun
bun run src/index.ts &
curl http://localhost:3000/health

# Wrangler (Cloudflare)
wrangler dev
curl http://localhost:8787/health

Step 2: Set Up HTTP Monitoring in Vigilmon

  1. Sign up at vigilmon.online (free, no card required)
  2. Click New Monitor → HTTP
  3. Enter https://your-worker.workers.dev/health (or your custom domain)
  4. Set check interval: 1 minute (paid) or 5 minutes (free)
  5. Expected status code: 200
  6. Save

For multi-region Hono deployments (Cloudflare's global network), Vigilmon checks from multiple probe regions independently, so a regional edge failure is distinguishable from a full outage.

Add monitors for your most critical routes alongside the health check:

https://your-worker.workers.dev/health     → process alive
https://your-worker.workers.dev/api/ping   → API routing works

Step 3: Latency Canary for Cold Start Detection

Hono on Cloudflare Workers starts cold when a Worker isolate is spun up fresh. Cold starts are usually <5ms for Hono itself but can spike with heavy initialization.

Add a latency canary endpoint:

health.get('/latency', async (c) => {
  const THRESHOLD_MS = 100;
  const start = performance.now();

  // Run a lightweight operation representative of real work
  await Promise.resolve(); // replace with a real DB ping
  const elapsed = Math.round(performance.now() - start);

  if (elapsed > THRESHOLD_MS) {
    return c.json({ slow: true, latencyMs: elapsed }, 503);
  }
  return c.json({ slow: false, latencyMs: elapsed });
});

Create a Vigilmon monitor for /health/latency expecting status 200. When cold starts or upstream slowness pushes latency above your threshold, you're alerted before SLA is breached.


Step 4: Heartbeat Monitoring for Scheduled Workers

Cloudflare Workers supports cron triggers via scheduled in wrangler.toml:

# wrangler.toml
[[triggers.crons]]
crons = ["0 * * * *"]  # every hour

Your Worker handles it:

// src/index.ts
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    return app.fetch(request, env);
  },

  async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void> {
    ctx.waitUntil(runHourlyJob(env));
  },
};

async function runHourlyJob(env: Env): Promise<void> {
  try {
    // your job logic here
    await processQueue(env);

    // Ping heartbeat on success
    if (env.VIGILMON_JOB_HEARTBEAT) {
      await fetch(env.VIGILMON_JOB_HEARTBEAT);
    }
  } catch (err) {
    console.error('Hourly job failed:', err);
    // No ping → Vigilmon alerts on missed heartbeat
  }
}

In wrangler.toml, add the secret binding:

[vars]
# set via wrangler secret put VIGILMON_JOB_HEARTBEAT

In Vigilmon:

  1. Click New Monitor → Heartbeat
  2. Set expected interval: 2 hours (generous buffer for the 1-hour cron)
  3. Copy the ping URL
  4. Run wrangler secret put VIGILMON_JOB_HEARTBEAT and paste it

If the cron trigger fires but the job throws, or if Cloudflare's cron scheduler misses an invocation, you get an alert.


Step 5: Slack Alerts

Go to Notifications → New Channel → Slack in Vigilmon and paste your incoming webhook URL. Enable it on your monitors.

When your Worker goes down:

🔴 DOWN: your-worker.workers.dev/health
Status: 503 Service Unavailable
Region: NA-East
1 minute ago

On recovery:

✅ RECOVERED: your-worker.workers.dev/health
Downtime: 4 minutes

Step 6: Error Handling Middleware

Add Hono error middleware to ensure unexpected exceptions return a proper 500 (not an empty response, which some monitoring tools can't distinguish from a timeout):

// src/index.ts
import { Hono } from 'hono';

const app = new Hono();

app.onError((err, c) => {
  console.error('Unhandled error:', err);
  return c.json({ error: 'Internal server error' }, 500);
});

app.notFound((c) => {
  return c.json({ error: 'Not found' }, 404);
});

// routes...
export default app;

Vigilmon treats 500 as a failure by default (you can configure expected status). With explicit 500 responses, downtime attribution is accurate.


What You've Built

| What | How | |------|-----| | Health endpoint | Hono route returning 200/503 based on dependency state | | HTTP uptime monitoring | Vigilmon HTTP monitor → /health | | Latency canary | /health/latency returns 503 on slow response | | Cron job monitoring | Heartbeat ping in scheduled() handler | | Slack alerts | Vigilmon Slack notification channel | | Error middleware | Explicit 500 on unhandled exceptions |

Your Hono app is now fully observable across any runtime. You'll know about outages and slowdowns before users report them.


Next Steps

  • Add a /health/upstream check that verifies third-party APIs your Hono app depends on
  • Monitor response time trends in Vigilmon — gradual slowdowns on a single region often precede wider failures
  • For Node.js deployments, add a process manager (PM2, systemd) restart heartbeat alongside the app heartbeat

Get started free at vigilmon.online.

Monitor your app with Vigilmon

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

Start free →