Server Log Analysis
Analysis Dashboard
Please go to the "Data Configuration" tab, paste your log data, and click "Analyze" to generate the dashboard.
Total Requests
0
404 Not Found
0
Server Errors (5xx)
0
Unique IPs
0
Status Code Breakdown
Requests by Hour
Top Lists
Please analyze your log data in the "Data Configuration" tab to view top lists.
Top Requested Pages
| Count | Page Path |
|---|
Top Visitors (IPs)
| Count | IP Address |
|---|
Top Referrers
| Count | Referrer URL |
|---|
Error Log (4xx & 5xx)
Please analyze your log data in the "Data Configuration" tab to view the error log.
| Raw Log Entry |
|---|
Data Configuration
Paste your server log data (e.g., Apache Combined Log Format) into the text box below and click "Analyze".
Load Sample Data
Click here to load USA-relevant sample data to test the tool.
Error: The tool could not be loaded. Please check the internet connection or contact the site administrator.
'; } return; } // --- Element Selection --- const tabLinks = document.querySelectorAll('.sla-tab-link'); const tabPanes = document.querySelectorAll('.sla-tab-pane'); const prevBtn = document.getElementById('sla-prev-btn'); const nextBtn = document.getElementById('sla-next-btn'); // Placeholders const dashboardPlaceholder = document.getElementById('sla-dashboard-placeholder'); const topListsPlaceholder = document.getElementById('sla-top-lists-placeholder'); const errorLogPlaceholder = document.getElementById('sla-error-log-placeholder'); // Content Wrappers const dashboardContent = document.getElementById('sla-dashboard-content'); const topListsContent = document.getElementById('sla-top-lists-content'); const errorLogContent = document.getElementById('sla-error-log-content'); // Config Tab const logInput = document.getElementById('sla-log-input'); const analyzeBtn = document.getElementById('sla-analyze-btn'); const loadSampleBtn = document.getElementById('sla-load-sample-btn'); // KPI Cards const kpiTotal = document.getElementById('sla-kpi-total'); const kpi404 = document.getElementById('sla-kpi-404'); const kpi5xx = document.getElementById('sla-kpi-5xx'); const kpiUniqueIPs = document.getElementById('sla-kpi-unique-ips'); // Tables const topPagesTable = document.getElementById('sla-top-pages-table').querySelector('tbody'); const topIPsTable = document.getElementById('sla-top-ips-table').querySelector('tbody'); const topReferrersTable = document.getElementById('sla-top-referrers-table').querySelector('tbody'); const errorLogTable = document.getElementById('sla-error-log-table').querySelector('tbody'); // PDF Button const downloadPdfBtn = document.getElementById('sla-download-pdf-btn'); // --- State --- let currentTab = 0; // Start at Dashboard (index 0) let statusChart; let requestsChart; // Regex for Apache Combined Log Format const logRegex = /^([(\d\.)]+) - - \[(.*?)\] "(.*?)" (\d{3}) (\d+|-) "(.*?)" "(.*)"$/; // --- Functions --- /** * Switches to the specified tab. * @param {number} tabIndex - The index of the tab to open. */ function openTab(tabIndex) { if (tabIndex < 0 || tabIndex >= tabLinks.length) return; // Hide all panes tabPanes.forEach(pane => pane.classList.remove('sla-active')); // Deactivate all links tabLinks.forEach(link => link.classList.remove('sla-active')); // Show selected pane and activate link if (tabPanes[tabIndex] && tabLinks[tabIndex]) { tabPanes[tabIndex].classList.add('sla-active'); tabLinks[tabIndex].classList.add('sla-active'); currentTab = tabIndex; } // Update Nav Button visibility if (prevBtn) prevBtn.style.display = (currentTab === 0) ? 'none' : 'inline-block'; if (nextBtn) nextBtn.style.display = (currentTab === tabLinks.length - 1) ? 'none' : 'inline-block'; } /** * Initializes the dashboard charts. */ function initializeCharts() { const statusCtx = document.getElementById('sla-status-chart')?.getContext('2d'); const requestsCtx = document.getElementById('sla-requests-chart')?.getContext('2d'); if (!statusCtx || !requestsCtx) { console.error("SLA Tool: Chart canvas elements not found."); return; } // Status Code Doughnut Chart statusChart = new Chart(statusCtx, { type: 'doughnut', data: { labels: ['2xx Success', '3xx Redirect', '4xx Client Error', '5xx Server Error', 'Other'], datasets: [{ data: [0, 0, 0, 0, 0], backgroundColor: [ 'rgba(40, 167, 69, 0.8)', 'rgba(0, 123, 255, 0.8)', 'rgba(255, 193, 7, 0.8)', 'rgba(220, 53, 69, 0.8)', 'rgba(108, 117, 125, 0.8)' ], borderWidth: 1 }] }, options: { responsive: true, plugins: { legend: { position: 'bottom', } } } }); // Requests by Hour Bar Chart requestsChart = new Chart(requestsCtx, { type: 'bar', data: { labels: Array.from({length: 24}, (_, i) => i.toString().padStart(2, '0') + ':00'), datasets: [{ label: 'Total Requests', data: Array(24).fill(0), backgroundColor: 'rgba(0, 123, 255, 0.6)', borderColor: 'rgba(0, 123, 255, 1)', borderWidth: 1, borderRadius: 4 }] }, options: { responsive: true, scales: { y: { beginAtZero: true, title: { display: true, text: 'Request Count' } }, x: { title: { display: true, text: 'Hour of Day' } } }, plugins: { legend: { display: false } } } }); } /** * Toggles the visibility of placeholders and content. * @param {boolean} showPlaceholders - True to show placeholders, false to show content. */ function togglePlaceholders(showPlaceholders) { const placeholderDisplay = showPlaceholders ? 'block' : 'none'; const contentDisplay = showPlaceholders ? 'none' : 'block'; if (dashboardPlaceholder) dashboardPlaceholder.style.display = placeholderDisplay; if (topListsPlaceholder) topListsPlaceholder.style.display = placeholderDisplay; if (errorLogPlaceholder) errorLogPlaceholder.style.display = placeholderDisplay; if (dashboardContent) dashboardContent.style.display = contentDisplay; if (topListsContent) topListsContent.style.display = contentDisplay; if (errorLogContent) errorLogContent.style.display = contentDisplay; if (downloadPdfBtn) downloadPdfBtn.style.display = contentDisplay; } /** * Sorts an object by its values in descending order. * @param {object} obj - The object to sort (e.g., { 'page': 10, 'page2': 5 }) * @returns {Array} - A sorted array of [key, value] pairs. */ function sortObjectByValue(obj) { return Object.entries(obj).sort(([,a],[,b]) => b-a); } /** * Main analysis function. */ function analyzeLogs() { const logData = logInput.value; if (!logData.trim()) { alert('Log data is empty. Please paste your logs or load the sample data.'); togglePlaceholders(true); return; } const lines = logData.trim().split('\n'); // Analysis data collectors let statusCounts = { '2xx': 0, '3xx': 0, '4xx': 0, '5xx': 0, 'other': 0 }; let error404Count = 0; let error5xxCount = 0; let pageCounts = {}; let ipCounts = {}; let referrerCounts = {}; let requestsByHour = Array(24).fill(0); let errorLines = []; let parsedLines = 0; lines.forEach(line => { const match = line.match(logRegex); if (!match) return; // Skip lines that don't match parsedLines++; const ip = match[1]; const timestampStr = match[2]; // e.g., "16/Nov/2025:15:20:01 +0000" const requestStr = match[3]; // e.g., "GET /page HTTP/1.1" const status = parseInt(match[4], 10); const referrer = match[6]; // 1. Count Statuses if (status >= 500) { statusCounts['5xx']++; error5xxCount++; errorLines.push(line); } else if (status === 404) { statusCounts['4xx']++; error404Count++; errorLines.push(line); } else if (status >= 400) { statusCounts['4xx']++; errorLines.push(line); } else if (status >= 300) { statusCounts['3xx']++; } else if (status >= 200) { statusCounts['2xx']++; } else { statusCounts['other']++; } // 2. Count IPs ipCounts[ip] = (ipCounts[ip] || 0) + 1; // 3. Count Pages try { const path = requestStr.split(' ')[1]; if (path) { pageCounts[path] = (pageCounts[path] || 0) + 1; } } catch (e) {} // Ignore malformed request strings // 4. Count Referrers if (referrer && referrer !== '-') { referrerCounts[referrer] = (referrerCounts[referrer] || 0) + 1; } // 5. Count Requests by Hour try { const hour = parseInt(timestampStr.split(':')[1], 10); if (!isNaN(hour) && hour >= 0 && hour <= 23) { requestsByHour[hour]++; } } catch (e) {} // Ignore malformed timestamps }); if (parsedLines === 0) { alert('Analysis complete, but 0 lines matched the Combined Log Format. Please check your log data.'); togglePlaceholders(true); return; } // --- Update UI --- togglePlaceholders(false); // 1. Update KPIs if(kpiTotal) kpiTotal.textContent = parsedLines.toLocaleString(); if(kpi404) kpi404.textContent = error404Count.toLocaleString(); if(kpi5xx) kpi5xx.textContent = error5xxCount.toLocaleString(); if(kpiUniqueIPs) kpiUniqueIPs.textContent = Object.keys(ipCounts).length.toLocaleString(); // 2. Update Charts if (statusChart) { statusChart.data.datasets[0].data = [ statusCounts['2xx'], statusCounts['3xx'], statusCounts['4xx'], statusCounts['5xx'], statusCounts['other'] ]; statusChart.update(); } if (requestsChart) { requestsChart.data.datasets[0].data = requestsByHour; requestsChart.update(); } // 3. Update Top Lists const topPages = sortObjectByValue(pageCounts); const topIPs = sortObjectByValue(ipCounts); const topReferrers = sortObjectByValue(referrerCounts); populateTable(topPagesTable, topPages.slice(0, 50)); populateTable(topIPsTable, topIPs.slice(0, 50)); populateTable(topReferrersTable, topReferrers.slice(0, 50)); // 4. Update Error Log if (errorLogTable) { errorLogTable.innerHTML = ''; if (errorLines.length === 0) { errorLogTable.innerHTML = '
Scroll to Top
