import React, { useState, useEffect } from 'react'; import api from '../api'; import { reportError, logUserActionError } from '../utils/errorLogger'; const LogMonitoringPage = ({ onNavigate, user }) => { const [activeTab, setActiveTab] = useState('login-logs'); // 'login-logs', 'activity-logs', 'system-logs' const [stats, setStats] = useState({ totalUsers: 0, activeUsers: 0, todayLogins: 0, failedLogins: 0, recentErrors: 0 }); const [recentActivity, setRecentActivity] = useState([]); const [activityLogs, setActivityLogs] = useState([]); const [frontendErrors, setFrontendErrors] = useState([]); const [isLoading, setIsLoading] = useState(true); const [message, setMessage] = useState({ type: '', text: '' }); useEffect(() => { loadDashboardData(); // 30초마다 자동 새로고침 const interval = setInterval(loadDashboardData, 30000); return () => clearInterval(interval); }, []); const loadActivityLogs = async () => { try { const response = await api.get('/auth/logs/system?limit=50'); if (response.data.success) { setActivityLogs(response.data.logs); } } catch (error) { console.error('활동 로그 로딩 실패:', error); } }; const loadDashboardData = async () => { try { setIsLoading(true); // 활동 로그도 함께 로드 if (activeTab === 'activity-logs') { await loadActivityLogs(); } // 병렬로 데이터 로드 const [usersResponse, loginLogsResponse] = await Promise.all([ api.get('/auth/users'), api.get('/auth/logs/login', { params: { limit: 20 } }) ]); // 사용자 통계 if (usersResponse.data.success) { const users = usersResponse.data.users; setStats(prev => ({ ...prev, totalUsers: users.length, activeUsers: users.filter(u => u.is_active).length })); } // 로그인 로그 통계 if (loginLogsResponse.data.success) { const logs = loginLogsResponse.data.logs; const today = new Date().toDateString(); const todayLogins = logs.filter(log => new Date(log.login_time).toDateString() === today && log.login_status === 'success' ).length; const failedLogins = logs.filter(log => new Date(log.login_time).toDateString() === today && log.login_status === 'failed' ).length; setStats(prev => ({ ...prev, todayLogins, failedLogins })); setRecentActivity(logs.slice(0, 10)); } // 프론트엔드 오류 로그 (로컬 스토리지에서) const localErrors = JSON.parse(localStorage.getItem('frontend_errors') || '[]'); const recentErrors = localErrors.filter(error => { const errorDate = new Date(error.timestamp); const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000); return errorDate > oneDayAgo; }); setFrontendErrors(recentErrors.slice(0, 10)); setStats(prev => ({ ...prev, recentErrors: recentErrors.length })); } catch (err) { console.error('Load dashboard data error:', err); setMessage({ type: 'error', text: '대시보드 데이터 로드 중 오류가 발생했습니다' }); logUserActionError('load_dashboard_data', err, { userId: user?.user_id }); } finally { setIsLoading(false); } }; const clearFrontendErrors = () => { localStorage.removeItem('frontend_errors'); setFrontendErrors([]); setStats(prev => ({ ...prev, recentErrors: 0 })); setMessage({ type: 'success', text: '프론트엔드 오류 로그가 삭제되었습니다' }); }; const formatDateTime = (dateString) => { try { return new Date(dateString).toLocaleString('ko-KR', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); } catch { return dateString; } }; const getActivityIcon = (status) => { return status === 'success' ? '✅' : '❌'; }; const getErrorTypeIcon = (type) => { const icons = { 'javascript_error': '❌', 'api_error': '🌐', 'user_action_error': '👤', 'promise_rejection': '⚠️', 'react_error_boundary': '⚛️' }; return icons[type] || '❓'; }; return (
📊 이 페이지는 30초마다 자동으로 새로고침됩니다