import React from 'react'; import { Container, Typography, Paper, Card, CardContent, List, ListItem, Tabs, Tab, Stack, Button, Box } from '@mui/material'; import { Navigate, Link } from 'react-router-dom'; import ArticleIcon from '@mui/icons-material/Article'; import { ADMIN_COLORS, getAdminStyles } from '../theme/adminColors.js'; class ServerLogsPage extends React.Component { constructor(props) { super(props); this.state = { user: null, loading: true, redirect: false, logs: [], historicalLogsLoaded: false }; } checkUserLoggedIn = () => { const storedUser = sessionStorage.getItem('user'); if (!storedUser) { this.setState({ redirect: true, user: null }); return; } try { const userData = JSON.parse(storedUser); if (!userData) { this.setState({ redirect: true, user: null }); } else if (!this.state.user) { // Only update user if it's not already set this.setState({ user: userData, loading: false }); } } catch (error) { console.error('Error parsing user from sessionStorage:', error); this.setState({ redirect: true, user: null }); } // Once loading is complete if (this.state.loading) { this.setState({ loading: false }); } } handleStorageChange = (e) => { if (e.key === 'user' && !e.newValue) { // User was removed from sessionStorage in another tab this.setState({ redirect: true, user: null }); } } handleLogEntry = (logEntry) => { console.log(`[${logEntry.timestamp}] ${logEntry.level.toUpperCase()}: ${logEntry.message}`); this.setState(prevState => ({ logs: [logEntry, ...prevState.logs].slice(0, 250) // Keep only last 250 logs })); } parseHistoricalLogLine = (logLine) => { // Try to parse JSON formatted log entries first try { const parsed = JSON.parse(logLine); if (parsed.level && parsed.message && parsed.timestamp) { return { timestamp: parsed.timestamp, level: parsed.level.toLowerCase(), message: parsed.message }; } } catch { // Not JSON, try other formats } // Try to parse bracket format like: "[2024-01-01T12:00:00.000Z] INFO: message content" const match = logLine.match(/^\[(.+?)\]\s+(\w+):\s*(.*)$/); if (match) { return { timestamp: match[1], level: match[2].toLowerCase(), message: match[3] }; } // Fallback for lines that don't match expected format return { timestamp: new Date().toISOString(), level: 'info', message: logLine }; } loadHistoricalLogs = () => { window.socketManager.emit('getLog', (response) => { if (response.success) { console.log('Last 50 historical logs:', response.data.lines); const historicalLogs = (response.data.lines || []) .map(line => this.parseHistoricalLogLine(line)) .reverse(); // Reverse to have newest first this.setState(prevState => ({ logs: [...historicalLogs, ...prevState.logs].slice(0, 250), historicalLogsLoaded: true })); } else { console.warn('Failed to load historical logs:', response); this.setState({ historicalLogsLoaded: true }); // Mark as attempted even if failed } }); } componentDidMount() { this.addSocketListeners(); this.checkUserLoggedIn(); this.loadHistoricalLogs(); // Load historical logs on mount // Set up interval to regularly check login status this.checkLoginInterval = setInterval(this.checkUserLoggedIn, 1000); // Add storage event listener to detect when user logs out in other tabs window.addEventListener('storage', this.handleStorageChange); } componentWillUnmount() { this.removeSocketListeners(); // Clear interval and remove event listeners if (this.checkLoginInterval) { clearInterval(this.checkLoginInterval); } window.removeEventListener('storage', this.handleStorageChange); } addSocketListeners = () => { // Remove existing listeners first to avoid duplicates this.removeSocketListeners(); window.socketManager.on('log', this.handleLogEntry); } removeSocketListeners = () => { window.socketManager.off('log', this.handleLogEntry); } formatLogLevel = (level) => { const colors = { error: ADMIN_COLORS.error, warn: ADMIN_COLORS.warning, info: ADMIN_COLORS.primary, debug: ADMIN_COLORS.secondary, verbose: ADMIN_COLORS.secondaryText }; return colors[level.toLowerCase()] || ADMIN_COLORS.primaryText; } clearLogs = () => { this.setState({ logs: [] }); } render() { if (this.state.redirect || (!this.state.loading && !this.state.user)) { return ; } // Check if current user is admin if (this.state.user && !this.state.user.admin) { return ; } const styles = getAdminStyles(); return ( {/* Admin Navigation Tabs */} {/* Server Logs Content */} Server Logs {this.state.logs.length === 0 ? ( {!this.state.historicalLogsLoaded ? "Loading historical logs..." : "No logs available. New logs will appear here in real-time."} ) : ( {this.state.logs.map((log, index) => ( {log.timestamp} {log.level}: {log.message} ))} )} ); } } export default ServerLogsPage;