Errors per Hour
${errorsPerHour}
Most Frequent Error
${mostFreqError}
Service Most Affected
${mostAffectedSvc}
`;
}
function renderAllCharts(data) {
const render = (id, type, chartData, options) => {
if(charts[id]) charts[id].destroy();
charts[id] = new Chart(document.getElementById(id), { type, data: chartData, options });
};
const chartOptions = { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#e2e8f0' } } } };
// Time Series Chart
const timeSeriesData = data.reduce((acc, row) => {
const hour = new Date(row.timestamp.setMinutes(0,0,0)).toISOString();
if(!acc[hour]) acc[hour] = {critical:0, error:0, warning:0};
acc[row.severity] = (acc[row.severity] || 0) + 1;
acc[hour][row.severity]++;
return acc;
}, {});
render('err-timeseries-chart', 'bar', {
labels: Object.keys(timeSeriesData),
datasets: ['critical', 'error', 'warning'].map(sev => ({
label: sev,
data: Object.values(timeSeriesData).map(d => d[sev]),
backgroundColor: severityColors[sev]
}))
}, { ...chartOptions, scales: { x: { type: 'time', time: { unit: 'hour' }, stacked: true, ticks:{color:'#94a3b8'} }, y: { stacked: true, ticks:{color:'#94a3b8'} } }, plugins: {...chartOptions.plugins, title:{display:true, text:'Errors by Severity Over Time', color:'#fff'}}});
// Breakdown charts
const typeData = data.reduce((acc,r) => {acc[r.error_type]=(acc[r.error_type]||0)+1; return acc;}, {});
const serviceData = data.reduce((acc,r) => {acc[r.service_name]=(acc[r.service_name]||0)+1; return acc;}, {});
render('err-type-chart', 'doughnut', { labels: Object.keys(typeData), datasets:[{ data: Object.values(typeData) }] }, {...chartOptions, plugins: {...chartOptions.plugins, title:{display:true, text:'Errors by Type', color:'#fff'}}});
render('err-service-chart', 'doughnut', { labels: Object.keys(serviceData), datasets:[{ data: Object.values(serviceData) }] }, {...chartOptions, plugins: {...chartOptions.plugins, title:{display:true, text:'Errors by Service', color:'#fff'}}});
}
function renderErrorLogTable(data) {
const searchTerm = elements.logSearch.value.toLowerCase();
const tableData = searchTerm ? data.filter(r => Object.values(r).join(' ').toLowerCase().includes(searchTerm)) : data;
elements.logTbody.innerHTML = tableData.slice(0, 200).map(row => `
| ${row.timestamp.toLocaleString()} |
${row.severity} |
${row.service_name} |
${row.error_type} |
${row.status_code || 'N/A'} |
`).join('');
}
window.errDownloadPDF = () => {
html2canvas(document.getElementById('err-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_Error_Dashboard.pdf');
});
};
});