Server Log Analysis Report Outline

Server Log Analysis

Analysis Dashboard

Please go to the "Data Configuration" tab, paste your log data, and click "Analyze" to generate the dashboard.

Top Lists

Please analyze your log data in the "Data Configuration" tab to view top lists.

Error Log (4xx & 5xx)

Please analyze your log data in the "Data Configuration" tab to view the error log.

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 = 'No errors found.'; } else { errorLines.forEach(line => { const row = errorLogTable.insertRow(); const cell = row.insertCell(0); cell.textContent = line; }); } } // Switch to dashboard openTab(0); } /** * Helper to populate a 2-column table from a sorted array. * @param {HTMLElement} tableBody - The element to populate. * @param {Array} data - The sorted [key, value] array. */ function populateTable(tableBody, data) { if (!tableBody) return; tableBody.innerHTML = ''; if (data.length === 0) { tableBody.innerHTML = 'No data available.'; return; } data.forEach(([key, value]) => { const row = tableBody.insertRow(); const cellCount = row.insertCell(0); const cellKey = row.insertCell(1); cellCount.textContent = value.toLocaleString(); cellKey.textContent = key; }); } /** * Loads sample data into the text area. */ function loadSampleData() { logInput.value = `68.180.224.110 - - [16/Nov/2025:10:01:34 -0500] "GET /products/widget-pro HTTP/1.1" 200 12543 "https://www.google.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" 108.59.14.7 - - [16/Nov/2025:10:02:11 -0500] "GET / HTTP/1.1" 200 8590 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" 68.180.224.110 - - [16/Nov/2025:10:02:35 -0500] "GET /assets/style.css HTTP/1.1" 200 23450 "https://example.com/products/widget-pro" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" 45.12.5.101 - - [16/Nov/2025:10:03:01 -0500] "GET /admin/login HTTP/1.1" 404 198 "https://www.bing.com/" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" 108.59.14.7 - - [16/Nov/2025:10:03:15 -0500] "GET /about-us HTTP/1.1" 200 4321 "https://example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" 72.21.217.170 - - [16/Nov/2025:10:04:00 -0500] "GET /old-page.html HTTP/1.1" 301 234 "https://www.google.com/" "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1" 68.180.224.110 - - [16/Nov/2025:10:04:30 -0500] "POST /cart/add HTTP/1.1" 200 150 "https://example.com/products/widget-pro" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" 192.0.2.1 - - [16/Nov/2025:11:15:10 -0500] "GET /checkout HTTP/1.1" 500 502 "https://example.com/cart" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" 45.12.5.101 - - [16/Nov/2025:11:16:02 -0500] "GET /wp-login.php HTTP/1.1" 404 198 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" 108.59.14.7 - - [16/Nov/2025:11:17:20 -0500] "GET /contact HTTP/1.1" 200 3011 "https://example.com/about-us" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" 192.0.2.1 - - [16/Nov/2025:11:20:11 -0500] "GET /checkout HTTP/1.1" 500 502 "https://example.com/cart" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" 68.180.224.110 - - [16/Nov/2025:13:05:00 -0500] "GET /products/widget-lite HTTP/1.1" 200 11987 "https://www.google.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" 45.12.5.101 - - [16/Nov/2025:13:06:15 -0500] "GET /config/db HTTP/1.1" 403 198 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" 192.0.2.1 - - [16/Nov/2025:13:07:01 -0500] "GET /api/v1/user HTTP/1.1" 503 502 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" 72.21.217.170 - - [16/Nov/2025:14:30:45 -0500] "GET / HTTP/1.1" 200 8590 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1"`; alert('Sample data loaded. Click "Analyze Logs" to process.'); } /** * Handles the PDF download functionality. */ async function downloadPDF() { const pdfArea = document.getElementById('sla-pdf-export-area'); if (!pdfArea) { console.error("SLA Tool: PDF export area not found."); return; } // Show a temporary loading state const originalButtonText = downloadPdfBtn.textContent; downloadPdfBtn.textContent = 'Generating...'; downloadPdfBtn.disabled = true; try { const canvas = await html2canvas(pdfArea, { scale: 2, // Higher resolution useCORS: true, logging: false }); const imgData = canvas.toDataURL('image/png'); // Get jsPDF from window object const { jsPDF } = window.jspdf; // A4 dimensions in mm: 210 x 297 const pdf = new jsPDF('p', 'mm', 'a4'); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const canvasWidth = canvas.width; const canvasHeight = canvas.height; // Calculate aspect ratio const imgHeight = (canvasHeight * pdfWidth) / canvasWidth; let heightLeft = imgHeight; let position = 10; // Top margin const leftMargin = 10; const contentWidth = pdfWidth - (leftMargin * 2); // Add image (handles multi-page) pdf.addImage(imgData, 'PNG', leftMargin, position, contentWidth, imgHeight); heightLeft -= (pdfHeight - 20); // Subtract first page (with margins) while (heightLeft > 0) { position = -heightLeft - 10; // Negative position moves canvas up pdf.addPage(); pdf.addImage(imgData, 'PNG', leftMargin, position, contentWidth, imgHeight); heightLeft -= (pdfHeight - 20); } pdf.save('server_log_analysis_report.pdf'); } catch (error) { console.error("SLA Tool: Error generating PDF:", error); alert("An error occurred while generating the PDF. Please try again."); } finally { // Restore button downloadPdfBtn.textContent = originalButtonText; downloadPdfBtn.disabled = false; } } // --- Event Listeners --- // Tab Navigation tabLinks.forEach((link, index) => { link.addEventListener('click', () => openTab(index)); }); if (prevBtn) prevBtn.addEventListener('click', () => { if (currentTab > 0) openTab(currentTab - 1); }); if (nextBtn) nextBtn.addEventListener('click', () => { if (currentTab < tabLinks.length - 1) openTab(currentTab + 1); }); // Config Tab Buttons if (analyzeBtn) { analyzeBtn.addEventListener('click', analyzeLogs); } if (loadSampleBtn) { loadSampleBtn.addEventListener('click', loadSampleData); } // PDF Download if (downloadPdfBtn) { downloadPdfBtn.addEventListener('click', downloadPDF); } // --- Initialization --- initializeCharts(); togglePlaceholders(true); // Start with placeholders visible openTab(0); // Start on the first tab (Dashboard) });
Scroll to Top