nginx-log-analyzer
Version:
124 lines (102 loc) • 3.84 kB
JavaScript
const fs = require("fs");
const readline = require("readline");
const chalk = require("chalk");
const uaParser = require("ua-parser-js");
// Function to analyze the log file
async function analyzeLogFile(filePath) {
const logData = {
totalRequests: 0,
statusCodes: {},
referrers: {},
urls: {},
browsers: {},
};
try {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
});
console.log(chalk.blue("Reading log file..."));
// Process each line of the log file
for await (const line of rl) {
// Extract relevant data from the log line
const logParts = line.match(/"([^"]*)"|(\S+)/g);
if (!logParts || logParts.length < 10) continue; // Skip malformed or empty lines
logData.totalRequests += 1; // Count only valid lines
const method = logParts[5]?.replace(/"/g, "").split(" ")[0];
const url = logParts[5]?.replace(/"/g, "").split(" ")[1];
const statusCode = logParts[6];
const referrer = logParts[8];
const userAgent = logParts[9]?.replace(/"/g, "");
// Count HTTP status codes
if (statusCode) {
logData.statusCodes[statusCode] =
(logData.statusCodes[statusCode] || 0) + 1;
}
if (referrer) {
logData.referrers[referrer] = (logData.referrers[referrer] || 0) + 1;
}
// Count accessed URLs
if (url) {
logData.urls[url] = (logData.urls[url] || 0) + 1;
}
// Parse User-Agent and count browsers
if (userAgent) {
const parsedUA = uaParser(userAgent);
const browserName = parsedUA.browser.name || "Unknown";
logData.browsers[browserName] = (logData.browsers[browserName] || 0) + 1;
}
}
console.log(chalk.green("Log analysis completed!"));
return logData;
} catch (error) {
console.error(chalk.red(`Error: ${error.message}`));
return null;
}
}
// Function to print analysis results
function printAnalysisResults(logData) {
if (!logData) {
console.log(chalk.red("Log analysis failed."));
return;
}
console.log(chalk.yellow("\n--- Log Analysis Results ---\n"));
console.log(chalk.green(`Total Requests: ${logData.totalRequests}`));
console.log(chalk.grey("\nReferrers:"));
for (const [status, count] of Object.entries(logData.referrers).sort(
(a, b) => b[1] - a[1]
)) {
const percentage = ((count / logData.totalRequests) * 100).toFixed(2);
console.log(` ${status}: ${count} (${percentage}%)`);
}
console.log(chalk.blue("\nHTTP Status Codes:"));
for (const [status, count] of Object.entries(logData.statusCodes).sort(
(a, b) => b[1] - a[1]
)) {
const percentage = ((count / logData.totalRequests) * 100).toFixed(2);
console.log(` ${status}: ${count} (${percentage}%)`);
}
console.log(chalk.magenta("\nMost Frequently Accessed PATHs:"));
const sortedUrls = Object.entries(logData.urls).sort((a, b) => b[1] - a[1]);
sortedUrls.slice(0, 10).forEach(([url, count]) => {
const percentage = ((count / logData.totalRequests) * 100).toFixed(2);
console.log(` ${url}: ${count} (${percentage}%)`);
});
console.log(chalk.cyan("\nTop Browsers:"));
const sortedBrowsers = Object.entries(logData.browsers).sort(
(a, b) => b[1] - a[1]
);
sortedBrowsers.slice(0, 5).forEach(([browser, count]) => {
const percentage = ((count / logData.totalRequests) * 100).toFixed(2);
console.log(` ${browser}: ${count} (${percentage}%)`);
});
}
// Read file path from command-line arguments and analyze the log
const logFilePath = process.argv[2];
if (!logFilePath) {
console.log(chalk.red("Log file parameter is required."));
process.exit();
}
analyzeLogFile(logFilePath).then(printAnalysisResults);