feat(admin/health): System Health Level 4 — диагностика + последние ошибки
adminController.getHealth: активные health-проверки — отклик БД (ping, мс) и
тест записи на диск рядом с БД; вердикт уходит в critical при недоступной БД
или диске, warning при медленном отклике БД (>100мс). Плюс recentErrorList —
последние 8 записей error_log (level/route/method/message/время).
admin.js: панель «Диагностика» — индикаторы БД/диска (зелёный/красный) +
лента последних ошибок с цветом по уровню.
Проверено: checks {dbOk,dbPingMs,diskWritable}, список ошибок отдаётся.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -648,6 +648,21 @@ function _dbTables() {
|
||||
} catch { return []; }
|
||||
}
|
||||
|
||||
// Активные проверки: отклик БД (мс) и тест записи на диск рядом с БД.
|
||||
function _runChecks() {
|
||||
let dbPingMs = null, dbOk = false;
|
||||
try { const t = process.hrtime.bigint(); db.prepare('SELECT 1 AS ok').get(); dbPingMs = Number(process.hrtime.bigint() - t) / 1e6; dbOk = true; } catch {}
|
||||
let diskWritable = false;
|
||||
try {
|
||||
const f = path.join(path.dirname(path.resolve(DB_PATH)), '.health-write-test');
|
||||
fs.writeFileSync(f, 'ok'); fs.unlinkSync(f); diskWritable = true;
|
||||
} catch {}
|
||||
return { dbPingMs, dbOk, diskWritable };
|
||||
}
|
||||
const _recentErrStmt = db.prepare(
|
||||
"SELECT id, level, message, route, method, created_at FROM error_log ORDER BY id DESC LIMIT 8"
|
||||
);
|
||||
|
||||
function getHealth(_req, res) {
|
||||
const uptimeSec = process.uptime();
|
||||
const mem = process.memoryUsage();
|
||||
@@ -672,6 +687,10 @@ function getHealth(_req, res) {
|
||||
let sseStats = { users: 0, guests: 0, connections: 0 };
|
||||
try { sseStats = sse.stats(); } catch {}
|
||||
|
||||
// Активные health-проверки (Level 4): отклик БД и запись на диск.
|
||||
const checks = _runChecks();
|
||||
const recentErrorList = (() => { try { return _recentErrStmt.all(); } catch { return []; } })();
|
||||
|
||||
// Вердикт здоровья по порогам.
|
||||
const reasons = [];
|
||||
let status = 'ok';
|
||||
@@ -688,9 +707,13 @@ function getHealth(_req, res) {
|
||||
if (eventLoopLagMs > 200) crit(`Лаг event-loop ${eventLoopLagMs.toFixed(0)} мс`);
|
||||
else if (eventLoopLagMs > 70) warn(`Лаг event-loop ${eventLoopLagMs.toFixed(0)} мс`);
|
||||
if (dbSizeBytes > 1.5e9) warn('БД >1.5 ГБ');
|
||||
if (!checks.dbOk) crit('БД недоступна');
|
||||
if (!checks.diskWritable) crit('Диск недоступен для записи');
|
||||
if (checks.dbPingMs != null && checks.dbPingMs > 100) warn(`Медленный отклик БД ${checks.dbPingMs.toFixed(0)} мс`);
|
||||
|
||||
res.json({
|
||||
status, reasons,
|
||||
checks, recentErrorList,
|
||||
uptime: uptimeSec,
|
||||
startedAt: new Date(Date.now() - uptimeSec * 1000).toISOString(),
|
||||
memory: { rss: mem.rss, heapUsed: mem.heapUsed, heapTotal: mem.heapTotal },
|
||||
|
||||
Reference in New Issue
Block a user