Files
0012/config/status-view.php
Frank Schwenk 85ab829805 feat: add monitoring dashboard under /monitor/
Status page and JSON API read from private/data; root index.php stays a placeholder. Mark todo 06 done.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-12 15:22:00 +02:00

104 lines
3.6 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/monitor-lib.php';
function loadStatusSnapshot(): array
{
$checksData = readJsonFile(privateDataDir() . '/last-checks.json');
$bokaData = readJsonFile(privateDataDir() . '/boka-status.json');
return [
'checks_data' => $checksData,
'boka_data' => $bokaData,
];
}
/** @param array{checks_data: ?array, boka_data: ?array} $snapshot */
function formatPublicStatus(array $snapshot): array
{
$checksData = $snapshot['checks_data'];
$bokaData = $snapshot['boka_data'];
if ($checksData === null && $bokaData === null) {
return [
'initialized' => false,
'message' => 'Monitoring not initialized',
'updated_at' => null,
'duration_ms' => null,
'checks' => [],
'boka' => null,
];
}
$checks = [];
foreach ($checksData['checks'] ?? [] as $check) {
if (!is_array($check)) {
continue;
}
$name = (string) ($check['name'] ?? '');
if ($name === '' || str_starts_with($name, '_')) {
continue;
}
$status = (string) ($check['status'] ?? 'down');
if (!in_array($status, ['ok', 'warn', 'down'], true)) {
$status = 'down';
}
$message = $check['message'] ?? null;
if (is_string($message) && $message !== '') {
$message = sanitizeError($message);
} else {
$message = null;
}
$checks[] = [
'name' => $name,
'status' => $status,
'message' => $message,
'response_ms' => isset($check['response_ms']) ? (int) $check['response_ms'] : null,
'ssl_days_remaining' => isset($check['ssl_days_remaining']) ? (int) $check['ssl_days_remaining'] : null,
'checked_at' => isset($check['checked_at']) && is_string($check['checked_at']) ? $check['checked_at'] : null,
];
}
$boka = null;
if ($bokaData !== null) {
$lastPush = $bokaData['last_push'] ?? null;
$ageMinutes = null;
if (is_string($lastPush) && $lastPush !== '') {
$lastPushAt = strtotime($lastPush) ?: 0;
if ($lastPushAt > 0) {
$ageMinutes = (int) floor((time() - $lastPushAt) / 60);
}
}
$boka = [
'host' => isset($bokaData['host']) && is_string($bokaData['host']) ? $bokaData['host'] : 'boka',
'last_push' => is_string($lastPush) ? $lastPush : null,
'age_minutes' => $ageMinutes,
'disk_percent' => isset($bokaData['disk_percent']) ? (int) $bokaData['disk_percent'] : null,
'mem_available_mb' => isset($bokaData['mem_available_mb']) ? (int) $bokaData['mem_available_mb'] : null,
'containers_running' => isset($bokaData['containers_running']) ? (int) $bokaData['containers_running'] : null,
'containers_unhealthy' => isset($bokaData['containers_unhealthy']) ? (int) $bokaData['containers_unhealthy'] : null,
'backup_last_success' => isset($bokaData['backup_last_success']) && is_string($bokaData['backup_last_success'])
? $bokaData['backup_last_success']
: null,
];
}
return [
'initialized' => $checksData !== null || $bokaData !== null,
'message' => null,
'updated_at' => isset($checksData['updated_at']) && is_string($checksData['updated_at'])
? $checksData['updated_at']
: null,
'duration_ms' => isset($checksData['duration_ms']) ? (int) $checksData['duration_ms'] : null,
'checks' => $checks,
'boka' => $boka,
];
}