From 49325ff1c34cdc9b6068c48b145d654ea162c231 Mon Sep 17 00:00:00 2001 From: Kieran Klukas Date: Sun, 15 Mar 2026 20:20:38 -0400 Subject: [PATCH] feat: update the status routes --- README.md | 82 +++++++++++++++++++++++++++++++++++++++++--- src/db.ts | 6 ++-- src/routes/index.ts | 6 ++-- src/routes/status.ts | 8 ++--- 4 files changed, 88 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 5fcfa8b..cdbf335 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,86 @@ The canonical repo for this is hosted on tangled over at [`dunkirk.sh/status`](h ## API +### `GET /api/status` +Overall summary with all machines and services. +```json +{ + "ok": true, + "status": "up", + "last_check": 1741900245, + "machines": [{ + "name": "orion", + "hostname": "orion", + "type": "server", + "online": true, + "status": "up", + "services": [{ + "id": "l4", + "status": "up", + "latency_ms": 42, + "uptime_90d": 99.84 + }] + }] +} ``` -/api/status # overall summary (ok, status, uptime, counts) -/api/status/overall # same as above -/api/status/service/:id # single service status + latency + uptime -/api/status/machine/:name # machine online status + all its services -/api/uptime/:service_id # hourly uptime buckets for a service + +### `GET /api/status/overall` +Lightweight overall summary. +```json +{ + "ok": true, + "status": "up", + "uptime_90d": 99.84, + "services_total": 20, + "services_monitored": 16, + "machines_total": 4 +} +``` + +### `GET /api/status/service/:id` +Single service status. +```json +{ + "id": "l4", + "status": "up", + "latency_ms": 42, + "uptime_90d": 99.84 +} +``` + +### `GET /api/status/machine/:name` +Machine and all its services. +```json +{ + "name": "orion", + "hostname": "orion", + "type": "server", + "online": true, + "status": "up", + "services": [{ + "id": "l4", + "status": "up", + "latency_ms": 42, + "uptime_90d": 99.84 + }] +} +``` + +### `GET /api/uptime/:service_id` +Hourly uptime buckets for a service. Optional `?window=` param (default: 90). +```json +{ + "service_id": "l4", + "window_hours": 2160, + "buckets": [{ + "timestamp": 1741896000, + "status": "up" + }] +} ``` +**Status values:** `up` · `degraded` · `down` · `partial` · `timeout` · `misconfigured` · `unknown` + ## Badges ``` diff --git a/src/db.ts b/src/db.ts index a7ee6c0..db9a0f8 100644 --- a/src/db.ts +++ b/src/db.ts @@ -29,8 +29,9 @@ export async function getLatestPing( export async function getUptime7d( db: D1Database, service_id: string, + days = 90, ): Promise { - const since = Math.floor(Date.now() / 1000) - 7 * 24 * 60 * 60; + const since = Math.floor(Date.now() / 1000) - days * 24 * 60 * 60; const row = await db .prepare( "SELECT COUNT(*) as total, SUM(CASE WHEN status = 'up' THEN 1 ELSE 0 END) as up_count FROM pings WHERE service_id = ? AND timestamp >= ?", @@ -66,8 +67,9 @@ export async function getAllLatestPings( export async function getAllUptime7d( db: D1Database, + days = 90, ): Promise> { - const since = Math.floor(Date.now() / 1000) - 7 * 24 * 60 * 60; + const since = Math.floor(Date.now() / 1000) - days * 24 * 60 * 60; const rows = await db .prepare( `SELECT service_id, COUNT(*) as total, SUM(CASE WHEN status = 'up' THEN 1 ELSE 0 END) as up_count diff --git a/src/routes/index.ts b/src/routes/index.ts index 15a7156..2ed47f6 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -33,7 +33,7 @@ export async function handleIndex(env: Env): Promise { url: `https://${svc.domain}`, status: latestPings.get(svc.name)?.status ?? "unknown", latency_ms: latestPings.get(svc.name)?.latency_ms ?? null, - uptime_7d: uptimes.get(svc.name) ?? 100, + uptime_90d: uptimes.get(svc.name) ?? 100, has_health: svc.health_url !== null, })); return { name, type: machine.type, online, services }; @@ -180,7 +180,7 @@ ${m.services.length === 0 ? `
no services
` : m.ser ${esc(s.name)}
- ${s.has_health ? `${s.uptime_7d}%${s.latency_ms !== null ? s.latency_ms + "ms" : "—"}` : `no health check`} + ${s.has_health ? `${s.uptime_90d}%${s.latency_ms !== null ? s.latency_ms + "ms" : "—"}` : `no health check`}
`, ) @@ -271,7 +271,7 @@ function applyUpdate(data) { const sDot = document.querySelector('[data-service="' + svc.id + '"]'); if (sDot) setDot(sDot, svc.status); const uEl = document.querySelector('[data-service-uptime="' + svc.id + '"]'); - if (uEl) uEl.textContent = svc.uptime_7d + '%'; + if (uEl) uEl.textContent = svc.uptime_90d + '%'; const lEl = document.querySelector('[data-service-latency="' + svc.id + '"]'); if (lEl) lEl.textContent = svc.latency_ms !== null ? svc.latency_ms + 'ms' : '—'; } diff --git a/src/routes/status.ts b/src/routes/status.ts index 5340c15..d045dcc 100644 --- a/src/routes/status.ts +++ b/src/routes/status.ts @@ -39,7 +39,7 @@ async function overallStatus(env: Env): Promise { { ok: grade === "up", status: grade, - uptime_7d: avgUptime, + uptime_90d: avgUptime, services_total: allServices.length, services_monitored: monitored.length, machines_total: Object.keys(manifest).length, @@ -64,7 +64,7 @@ async function fullStatus(env: Env): Promise { id: svc.name, status: (ping?.status ?? "unknown") as string, latency_ms: ping?.latency_ms ?? null, - uptime_7d: uptimes.get(svc.name) ?? 100, + uptime_90d: uptimes.get(svc.name) ?? 100, }; }); const svcStatuses = services.map((s) => s.status); @@ -106,7 +106,7 @@ async function serviceStatus(env: Env, id: string): Promise { id, status: ping.status, latency_ms: ping.latency_ms, - uptime_7d: uptime, + uptime_90d: uptime, } ); } @@ -128,7 +128,7 @@ async function machineStatus(env: Env, name: string): Promise { id: svc.name, status: (ping?.status ?? "unknown") as string, latency_ms: ping?.latency_ms ?? null, - uptime_7d: uptime, + uptime_90d: uptime, }; }), ); -- 2.51.2