diff --git a/frontend/src/components/debug/ResourceDebugOverlay.tsx b/frontend/src/components/debug/ResourceDebugOverlay.tsx index b37eb453..da09a6c2 100644 --- a/frontend/src/components/debug/ResourceDebugOverlay.tsx +++ b/frontend/src/components/debug/ResourceDebugOverlay.tsx @@ -137,13 +137,18 @@ export default function ResourceDebugOverlay({ enabled }: ResourceDebugOverlayPr }); if (response.ok) { - const data = await response.json(); + const responseData = await response.json(); + // Extract data from unified API response format: {success: true, data: {...}} + const data = responseData?.data || responseData; // Only log in debug mode to reduce console noise if (import.meta.env.DEV) { console.debug('Fetched metrics for request:', requestId, data); } - metricsRef.current = [...metricsRef.current, data]; - setMetrics([...metricsRef.current]); + // Validate data structure before adding + if (data && typeof data === 'object' && data.request_id) { + metricsRef.current = [...metricsRef.current, data]; + setMetrics([...metricsRef.current]); + } } else if (response.status === 401) { // Token might be expired - try to refresh and retry once try { @@ -160,9 +165,14 @@ export default function ResourceDebugOverlay({ enabled }: ResourceDebugOverlayPr credentials: 'include', }); if (retryResponse.ok) { - const data = await retryResponse.json(); - metricsRef.current = [...metricsRef.current, data]; - setMetrics([...metricsRef.current]); + const responseData = await retryResponse.json(); + // Extract data from unified API response format: {success: true, data: {...}} + const data = responseData?.data || responseData; + // Validate data structure before adding + if (data && typeof data === 'object' && data.request_id) { + metricsRef.current = [...metricsRef.current, data]; + setMetrics([...metricsRef.current]); + } return; } } @@ -191,14 +201,23 @@ export default function ResourceDebugOverlay({ enabled }: ResourceDebugOverlayPr // Calculate page load time const pageLoadTime = pageLoadStart ? performance.now() - pageLoadStart : null; - // Calculate totals - const totals = metrics.reduce((acc, m) => ({ - elapsed_time_ms: acc.elapsed_time_ms + m.elapsed_time_ms, - cpu_total_ms: acc.cpu_total_ms + m.cpu.total_time_ms, - memory_delta_mb: acc.memory_delta_mb + m.memory.delta_mb, - io_read_mb: acc.io_read_mb + m.io.read_mb, - io_write_mb: acc.io_write_mb + m.io.write_mb, - }), { + // Calculate totals - with null safety checks + const totals = metrics.reduce((acc, m) => { + // Safely access nested properties with defaults + const elapsed = m?.elapsed_time_ms || 0; + const cpuTotal = m?.cpu?.total_time_ms || 0; + const memoryDelta = m?.memory?.delta_mb || 0; + const ioRead = m?.io?.read_mb || 0; + const ioWrite = m?.io?.write_mb || 0; + + return { + elapsed_time_ms: acc.elapsed_time_ms + elapsed, + cpu_total_ms: acc.cpu_total_ms + cpuTotal, + memory_delta_mb: acc.memory_delta_mb + memoryDelta, + io_read_mb: acc.io_read_mb + ioRead, + io_write_mb: acc.io_write_mb + ioWrite, + }; + }, { elapsed_time_ms: 0, cpu_total_ms: 0, memory_delta_mb: 0, @@ -206,25 +225,31 @@ export default function ResourceDebugOverlay({ enabled }: ResourceDebugOverlayPr io_write_mb: 0, }); - // Find the slowest request + // Find the slowest request - with null safety const slowestRequest = metrics.length > 0 - ? metrics.reduce((prev, current) => - (current.elapsed_time_ms > prev.elapsed_time_ms) ? current : prev - ) + ? metrics.reduce((prev, current) => { + const prevTime = prev?.elapsed_time_ms || 0; + const currentTime = current?.elapsed_time_ms || 0; + return (currentTime > prevTime) ? current : prev; + }) : null; - // Find the request with highest CPU usage + // Find the request with highest CPU usage - with null safety const highestCpuRequest = metrics.length > 0 - ? metrics.reduce((prev, current) => - (current.cpu.total_time_ms > prev.cpu.total_time_ms) ? current : prev - ) + ? metrics.reduce((prev, current) => { + const prevCpu = prev?.cpu?.total_time_ms || 0; + const currentCpu = current?.cpu?.total_time_ms || 0; + return (currentCpu > prevCpu) ? current : prev; + }) : null; - // Find the request with highest memory usage + // Find the request with highest memory usage - with null safety const highestMemoryRequest = metrics.length > 0 - ? metrics.reduce((prev, current) => - (current.memory.delta_mb > prev.memory.delta_mb) ? current : prev - ) + ? metrics.reduce((prev, current) => { + const prevMemory = prev?.memory?.delta_mb || 0; + const currentMemory = current?.memory?.delta_mb || 0; + return (currentMemory > prevMemory) ? current : prev; + }) : null; if (!enabled || !isAdminOrDeveloper) return null; @@ -272,23 +297,23 @@ export default function ResourceDebugOverlay({ enabled }: ResourceDebugOverlayPr
{slowestRequest && (
- Slowest Request: {slowestRequest.method} {slowestRequest.path} + Slowest Request: {slowestRequest.method || 'N/A'} {slowestRequest.path || 'N/A'}
- Time: {slowestRequest.elapsed_time_ms.toFixed(2)} ms + Time: {(slowestRequest.elapsed_time_ms || 0).toFixed(2)} ms
)} - {highestCpuRequest && highestCpuRequest.cpu.total_time_ms > 100 && ( + {highestCpuRequest && highestCpuRequest.cpu && (highestCpuRequest.cpu.total_time_ms || 0) > 100 && (
- Highest CPU: {highestCpuRequest.method} {highestCpuRequest.path} + Highest CPU: {highestCpuRequest.method || 'N/A'} {highestCpuRequest.path || 'N/A'}
- CPU: {highestCpuRequest.cpu.total_time_ms.toFixed(2)} ms (System: {highestCpuRequest.cpu.system_percent.toFixed(1)}%) + CPU: {(highestCpuRequest.cpu.total_time_ms || 0).toFixed(2)} ms (System: {(highestCpuRequest.cpu.system_percent || 0).toFixed(1)}%)
)} - {highestMemoryRequest && highestMemoryRequest.memory.delta_mb > 1 && ( + {highestMemoryRequest && highestMemoryRequest.memory && (highestMemoryRequest.memory.delta_mb || 0) > 1 && (
- Highest Memory: {highestMemoryRequest.method} {highestMemoryRequest.path} + Highest Memory: {highestMemoryRequest.method || 'N/A'} {highestMemoryRequest.path || 'N/A'}
- Memory: {highestMemoryRequest.memory.delta_mb > 0 ? '+' : ''}{highestMemoryRequest.memory.delta_mb.toFixed(2)} MB + Memory: {(highestMemoryRequest.memory.delta_mb || 0) > 0 ? '+' : ''}{(highestMemoryRequest.memory.delta_mb || 0).toFixed(2)} MB
)}
@@ -321,9 +346,14 @@ export default function ResourceDebugOverlay({ enabled }: ResourceDebugOverlayPr ) : ( metrics.map((m, idx) => { - const isSlow = m.elapsed_time_ms > 1000; - const isHighCpu = m.cpu.total_time_ms > 100; - const isHighMemory = m.memory.delta_mb > 1; + // Safely access properties with defaults + const elapsedTime = m?.elapsed_time_ms || 0; + const cpuTotal = m?.cpu?.total_time_ms || 0; + const memoryDelta = m?.memory?.delta_mb || 0; + + const isSlow = elapsedTime > 1000; + const isHighCpu = cpuTotal > 100; + const isHighMemory = memoryDelta > 1; return (
- ⏱️ Time: {m.elapsed_time_ms.toFixed(2)} ms + ⏱️ Time: {elapsedTime.toFixed(2)} ms
-
- 🔥 CPU: {m.cpu.total_time_ms.toFixed(2)} ms - (User: {m.cpu.user_time_ms.toFixed(2)}ms, System: {m.cpu.system_time_ms.toFixed(2)}ms) -
- System CPU: {m.cpu.system_percent.toFixed(1)}% -
-
- 💾 Memory: {m.memory.delta_mb > 0 ? '+' : ''}{m.memory.delta_mb.toFixed(2)} MB - (Final RSS: {m.memory.final_rss_mb.toFixed(2)} MB) -
- System Memory: {m.memory.system_used_percent.toFixed(1)}% -
- {m.io.read_mb > 0 && ( -
- 📖 I/O Read: {m.io.read_mb.toFixed(2)} MB ({m.io.read_bytes.toLocaleString()} bytes) + {m?.cpu && ( +
+ 🔥 CPU: {cpuTotal.toFixed(2)} ms + (User: {(m.cpu.user_time_ms || 0).toFixed(2)}ms, System: {(m.cpu.system_time_ms || 0).toFixed(2)}ms) +
+ System CPU: {(m.cpu.system_percent || 0).toFixed(1)}%
)} - {m.io.write_mb > 0 && ( + {m?.memory && ( +
+ 💾 Memory: {memoryDelta > 0 ? '+' : ''}{memoryDelta.toFixed(2)} MB + (Final RSS: {(m.memory.final_rss_mb || 0).toFixed(2)} MB) +
+ System Memory: {(m.memory.system_used_percent || 0).toFixed(1)}% +
+ )} + {m?.io?.read_mb > 0 && (
- 📝 I/O Write: {m.io.write_mb.toFixed(2)} MB ({m.io.write_bytes.toLocaleString()} bytes) + 📖 I/O Read: {m.io.read_mb.toFixed(2)} MB ({(m.io.read_bytes || 0).toLocaleString()} bytes) +
+ )} + {m?.io?.write_mb > 0 && ( +
+ 📝 I/O Write: {m.io.write_mb.toFixed(2)} MB ({(m.io.write_bytes || 0).toLocaleString()} bytes)
)}