diff --git a/backend/src/controllers/adminController.js b/backend/src/controllers/adminController.js index 9c6ce00..76a235f 100644 --- a/backend/src/controllers/adminController.js +++ b/backend/src/controllers/adminController.js @@ -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 }, diff --git a/frontend/js/admin/admin.js b/frontend/js/admin/admin.js index b024712..830485c 100644 --- a/frontend/js/admin/admin.js +++ b/frontend/js/admin/admin.js @@ -388,6 +388,30 @@ `; } + // ── панель диагностики (Level 4): health-чеки + последние ошибки ── + let diagHtml = ''; + { + const ch = h.checks || {}; + const okCol = '#4ade80', badCol = 'var(--pink)'; + const chip = (label, ok, extra) => `