/** * API Logs Panel Component * * Real-time API request monitoring with: * - Request list with filtering * - Response time statistics * - Top endpoints * - Status code breakdown */ import React, { useState, useEffect, useCallback } from 'react'; import { Activity, RefreshCw, Filter, Clock, ArrowUpRight, ArrowDownRight, Check, XCircle, AlertTriangle, Zap, BarChart3, TrendingUp } from 'lucide-react'; import { getToken } from '../../services/api'; const API_BASE = import.meta.env.VITE_API_URL || ''; // HTTP Method badge const MethodBadge = ({ method }) => { const colors = { GET: { bg: '#dbeafe', color: '#2563eb' }, POST: { bg: '#d1fae5', color: '#059669' }, PUT: { bg: '#fef3c7', color: '#d97706' }, DELETE: { bg: '#fee2e2', color: '#dc2626' }, PATCH: { bg: '#ede9fe', color: '#7c3aed' } }; const { bg, color } = colors[method] || { bg: '#f3f4f6', color: '#374151' }; return ( {method} ); }; // Status code badge const StatusBadge = ({ code }) => { let bg, color; if (code >= 500) { bg = '#fee2e2'; color = '#dc2626'; } else if (code >= 400) { bg = '#fef3c7'; color = '#d97706'; } else if (code >= 300) { bg = '#dbeafe'; color = '#2563eb'; } else { bg = '#d1fae5'; color = '#059669'; } return ( {code} ); }; // Response time indicator const ResponseTimeIndicator = ({ ms }) => { let color; if (ms < 100) color = '#10b981'; else if (ms < 500) color = '#f59e0b'; else color = '#ef4444'; return ( {ms.toFixed(0)}ms ); }; function APILogsPanel() { const [logs, setLogs] = useState([]); const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Filters const [endpoint, setEndpoint] = useState(''); const [method, setMethod] = useState(''); const [statusCode, setStatusCode] = useState(''); const [limit, setLimit] = useState(100); const [autoRefresh, setAutoRefresh] = useState(true); // Fetch logs const fetchLogs = useCallback(async () => { setLoading(true); setError(null); try { const token = getToken(); const params = new URLSearchParams({ limit: limit.toString() }); if (endpoint) params.append('endpoint', endpoint); if (method) params.append('method', method); if (statusCode) params.append('status_code', statusCode); const response = await fetch(`${API_BASE}/api/admin/api-logs?${params}`, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } }); if (!response.ok) throw new Error('Failed to fetch API logs'); const data = await response.json(); if (data.success) { setLogs(data.logs); setStats(data.stats); } } catch (err) { setError(err.message); } finally { setLoading(false); } }, [endpoint, method, statusCode, limit]); // Initial fetch useEffect(() => { fetchLogs(); }, [fetchLogs]); // Auto-refresh every 10 seconds useEffect(() => { if (!autoRefresh) return; const interval = setInterval(fetchLogs, 10000); return () => clearInterval(interval); }, [autoRefresh, fetchLogs]); if (loading) { return (

Loading API logs...

); } return (
{/* Header */}

API Request Logs

{/* Stats Cards */} {stats && (
{stats.total_requests || 0} Total Requests (24h)
{stats.avg_response_time?.toFixed(0) || 0}ms Avg Response Time
{stats.status_breakdown?.['2xx'] || 0} Successful (2xx)
{(stats.status_breakdown?.['4xx'] || 0) + (stats.status_breakdown?.['5xx'] || 0)} Errors (4xx/5xx)
)} {/* Top Endpoints */} {stats?.top_endpoints && stats.top_endpoints.length > 0 && (

Top Endpoints

{stats.top_endpoints.map((ep, idx) => (
#{idx + 1} {ep.endpoint} {ep.count} requests
))}
)} {/* Filters */}
setEndpoint(e.target.value)} />
{/* Logs Table */}
{logs.length === 0 ? ( ) : ( logs.map((log) => ( )) )}
Method Endpoint Status Response Time IP Address Time
No API logs found
{log.endpoint} {log.ip_address} {new Date(log.created_at).toLocaleTimeString()}
); } export default APILogsPanel;