Application Response Time Tracker

${title}

${value}

`).join(''); } function renderTimeSeriesChart(data) { if(data.length === 0) return; const timeBuckets = data.reduce((acc, row) => { const bucketTime = new Date(row.timestamp); bucketTime.setMinutes(Math.floor(bucketTime.getMinutes()/5)*5, 0, 0); // 5-min buckets const key = bucketTime.toISOString(); if(!acc[key]) acc[key] = []; acc[key].push(row.response_time_ms); return acc; }, {}); const chartData = Object.entries(timeBuckets).map(([time, times]) => { const sortedTimes = times.sort((a,b) => a-b); return { x: time, p50: getPercentile(sortedTimes, 0.50), p95: getPercentile(sortedTimes, 0.95), p99: getPercentile(sortedTimes, 0.99) }; }); if(charts.time) charts.time.destroy(); charts.time = new Chart('resp-timeseries-chart', { type: 'line', data: { datasets: [ { label: 'p50', data: chartData.map(d=>({x:d.x, y:d.p50})), borderColor: '#3b82f6', tension: 0.2, pointRadius: 0 }, { label: 'p95', data: chartData.map(d=>({x:d.x, y:d.p95})), borderColor: '#f97316', tension: 0.2, pointRadius: 0 }, { label: 'p99', data: chartData.map(d=>({x:d.x, y:d.p99})), borderColor: '#ef4444', tension: 0.2, pointRadius: 0 } ] }, options: { responsive: true, maintainAspectRatio: false, scales: { x: { type: 'time', time: { unit: 'minute' }, ticks:{color:'#94a3b8'} }, y: { ticks:{color:'#94a3b8'}, title:{display:true, text:'Response Time (ms)', color:'#94a3b8'} } }, plugins: { legend:{labels:{color:'#e2e8f0'}}} } }); } function renderEndpointTable(data) { const endpointGroups = data.reduce((acc, row) => { if(!acc[row.endpoint]) acc[row.endpoint] = []; acc[row.endpoint].push(row); return acc; }, {}); let tableData = Object.entries(endpointGroups).map(([endpoint, rows]) => { const successRows = rows.filter(r => r.success); const responseTimes = successRows.map(r => r.response_time_ms).sort((a,b)=>a-b); return { endpoint, count: rows.length, avg: (responseTimes.reduce((a,b)=>a+b,0) / responseTimes.length || 0), p95: getPercentile(responseTimes, 0.95), errorRate: (1 - successRows.length / rows.length) * 100 }; }); tableData.sort((a,b) => { const valA = a[endpointSort.key]; const valB = b[endpointSort.key]; if(endpointSort.order === 'asc') return valA - valB; return valB - valA; }); const headers = [ { key: 'endpoint', name: 'Endpoint' }, { key: 'count', name: 'Requests' }, { key: 'avg', name: 'Avg Time (ms)' }, { key: 'p95', name: 'p95 Time (ms)' }, { key: 'errorRate', name: 'Error Rate' } ]; elements.tableHead.innerHTML = `${headers.map(h => `${h.name}${endpointSort.key === h.key ? (endpointSort.order === 'desc' ? ' â–¼' : ' â–²') : ''}`).join('')}`; elements.tableBody.innerHTML = tableData.map(row => ` ${row.endpoint} ${row.count} ${row.avg.toFixed(0)} ${row.p95.toFixed(0)} ${row.errorRate.toFixed(1)}% `).join(''); } elements.tableHead.addEventListener('click', (e) => { if(e.target.tagName === 'TH') { const key = e.target.dataset.key; if(endpointSort.key === key) { endpointSort.order = endpointSort.order === 'asc' ? 'desc' : 'asc'; } else { endpointSort.key = key; endpointSort.order = 'desc'; } updateDashboard(); } }); window.respDownloadPDF = () => { html2canvas(document.getElementById('resp-dashboard-output'), { backgroundColor: '#0f172a', scale: 2 }).then(canvas => { const pdf = new jspdf.jsPDF({ orientation: 'landscape', unit: 'pt', format: 'a4' }); pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 40, 40, pdf.internal.pageSize.getWidth() - 80, 0); pdf.save('Application_Response_Time_Dashboard.pdf'); }); }; });
Scroll to Top