'use client'; import { useState, useEffect } from 'react'; import Sidebar from '@/components/Sidebar'; interface HealthStatus { status: 'healthy' | 'degraded' | 'unhealthy'; checks: { database: { status: 'ok' | 'error'; message?: string }; redis: { status: 'ok' | 'error'; message?: string }; disk: { status: 'ok' | 'error'; message?: string; freeSpace?: number }; }; timestamp: string; } export default function MonitoringPage() { const [health, setHealth] = useState(null); const [metrics, setMetrics] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { loadData(); const interval = setInterval(loadData, 30000); // Обновление каждые 30 секунд return () => clearInterval(interval); }, []); const loadData = async () => { try { setLoading(true); const [healthRes, metricsRes] = await Promise.all([ fetch('/api/health').catch(err => { console.warn('[Monitoring] Ошибка загрузки health:', err); return { ok: false, json: async () => ({ status: 'unhealthy', checks: {}, timestamp: new Date() }) }; }), fetch('/api/metrics?type=performance').catch(err => { console.warn('[Monitoring] Ошибка загрузки metrics:', err); return { ok: false, json: async () => ({ stats: { count: 0, avgDuration: 0, minDuration: 0, maxDuration: 0, errorRate: 0 } }) }; }), ]); const healthData = await healthRes.json(); const metricsData = await metricsRes.json(); console.log('[Monitoring] Данные загружены:', { health: healthData.status, metrics: metricsData.stats?.count || 0 }); setHealth(healthData); setMetrics(metricsData); } catch (error: any) { console.error('[Monitoring] Ошибка загрузки данных мониторинга:', error); setHealth(null); setMetrics(null); } finally { setLoading(false); } }; const getStatusColor = (status: string) => { switch (status) { case 'healthy': case 'ok': return '#4caf50'; case 'degraded': return '#ff9800'; case 'unhealthy': case 'error': return '#f44336'; default: return '#666'; } }; const getStatusText = (status: string) => { switch (status) { case 'healthy': return 'Здоров'; case 'degraded': return 'Работает (некритичные предупреждения)'; case 'unhealthy': return 'Неисправен'; default: return status; } }; return (

Мониторинг системы

Состояние системы и метрики производительности

{loading ? (
Загрузка данных мониторинга...
) : ( <> {/* Health Status */} {health && (

Состояние системы

Общий статус: {getStatusText(health.status)}
Последняя проверка: {new Date(health.timestamp).toLocaleString('ru-RU')}
{health.status === 'degraded' && (
⚠️ Система работает в режиме без БД/Redis (используются мок-данные)
)}
{health.status === 'degraded' ? 'DEGRADED' : health.status.toUpperCase()}
{Object.entries(health.checks).map(([key, check]) => (
{key === 'database' ? 'База данных' : key === 'redis' ? 'Redis' : 'Диск'}
{check.status === 'ok' ? '✓ Работает' : `✗ Ошибка: ${check.message || 'Неизвестная ошибка'}`}
{'freeSpace' in check && check.freeSpace !== undefined && (
Свободно: {check.freeSpace}%
)}
))}
)} {/* Performance Metrics */} {metrics && metrics.stats && (

Метрики производительности

Всего запросов
{metrics.stats.count}
Среднее время ответа
{metrics.stats.avgDuration.toFixed(0)}ms
Минимальное время
{metrics.stats.minDuration}ms
Максимальное время
{metrics.stats.maxDuration}ms
Процент ошибок
0.1 ? '#f44336' : '#4caf50' }}> {(metrics.stats.errorRate * 100).toFixed(1)}%
)} )}
); }