[ connect ]
Monitor your self-hosted app
Deploying on a VPS, Docker, or your own CI? You don't need an AI tool — wire up monitoring by hand in two small pieces: a health endpoint CanaryHub polls, and fire-and-forget error reporting. Pick your stack below.
1 · Add a health endpoint + error reporting
The health endpoint returns ok, degraded, or down with one entry in checksper critical dependency. It must be public, fast (<2s), and side-effect free. Error reporting must never block or crash a request.
Next.js (App Router)
import { NextResponse } from "next/server";export const dynamic = "force-dynamic";export async function GET() { const started = performance.now(); let db = "ok"; try { await sql`SELECT 1`; // your DB client here } catch { db = "down"; } const latencyMs = Math.round(performance.now() - started); return NextResponse.json({ status: db === "ok" ? "ok" : "down", version: process.env.GIT_SHA ?? "dev", checks: [{ name: "database", status: db, latencyMs }], });}$ npm install @canaryhub/sdk// once at startup (instrumentation.ts or your server entry):import { canary } from "@canaryhub/sdk";canary.init("ch_live_YOUR_KEY_HERE");// wherever you catch an unexpected server error:canary.error("checkout_failed", { message: String(err) });Express
import express from "express";import { canary } from "@canaryhub/sdk";canary.init("ch_live_YOUR_KEY_HERE");const app = express();app.get("/api/health", async (_req, res) => { const started = performance.now(); let db = "ok"; try { await pool.query("SELECT 1"); // your DB client here } catch { db = "down"; } res.json({ status: db === "ok" ? "ok" : "down", version: process.env.GIT_SHA ?? "dev", checks: [{ name: "database", status: db, latencyMs: Math.round(performance.now() - started) }], });});// last middleware — report, then keep normal error handling:app.use((err, _req, res, _next) => { canary.error("unhandled_error", { message: String(err) }); res.status(500).json({ error: "internal error" });});FastAPI
import os, time, httpxfrom fastapi import FastAPI, Requestfrom fastapi.responses import JSONResponseapp = FastAPI()INGEST = "https://ingest.canaryhub.ai/api/v1/events"KEY = "ch_live_YOUR_KEY_HERE"@app.get("/api/health")async def health(): started = time.monotonic() db = "ok" try: await database.execute("SELECT 1") # your DB client here except Exception: db = "down" latency_ms = round((time.monotonic() - started) * 1000) return { "status": "ok" if db == "ok" else "down", "version": os.environ.get("GIT_SHA", "dev"), "checks": [{"name": "database", "status": db, "latencyMs": latency_ms}], }@app.exception_handler(Exception)async def report_error(request: Request, exc: Exception): # report is capped at 2 s; a monitoring outage must never take down a request try: async with httpx.AsyncClient(timeout=2) as client: await client.post( INGEST, headers={"Authorization": f"Bearer {KEY}"}, json={"events": [{"type": "error", "name": type(exc).__name__, "message": str(exc)[:2000]}]}, ) except Exception: pass return JSONResponse(status_code=500, content={"error": "internal error"})Replace ch_live_YOUR_KEY_HERE with a real key — sign up free and create one under API keys.
2 · Verify it worked
Deploy, then open yourapp.com/api/health in a browser — you should see the JSON above. Events show up live in your dashboard.
Different language? Anything that can serve JSON and make an HTTP POST can do this — the full contract is in the HTTP API docs.