From ecf0bcc9b00a37119d529fa7eb3863e566df9fcb Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Tue, 23 Aug 2022 23:34:24 -0400 Subject: [PATCH] Ability to write out JSON data to a file for later collection. --- 02-filter-a-log-file/chains_parser.js | 56 +++++++++++++++++++++------ 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/02-filter-a-log-file/chains_parser.js b/02-filter-a-log-file/chains_parser.js index ce8dae5..1081367 100644 --- a/02-filter-a-log-file/chains_parser.js +++ b/02-filter-a-log-file/chains_parser.js @@ -243,10 +243,12 @@ const construct_request_chains = (by_ip, domain, as_set) => { return ip_chains; } -const sort_request_chains = (chains) => { +const sort_request_chains = (chains, min) => { const converted = []; for(let [url, stats] of Object.entries(chains)) { + if(stats.count < min) continue; // skip below min + if(stats.comes_from) { converted.push([stats.count, `[${stats.comes_from}] ${stats.full_chain.join(' ')}`]); } else { @@ -257,14 +259,39 @@ const sort_request_chains = (chains) => { return converted.sort((a, b) => b[0] - a[0]); } -const output_results = (chains_sorted, min) => { - for(let [count, url] of chains_sorted) { - if(count >= min) { +const output_results = async (stats, chains, format, outfile) => { + if(format === "json") { + const data = {stats, chains, date: new Date()}; + console.log(data); + } else { + const chains_sorted = sort_request_chains(chains, OPTS.min); + + for(let [count, url] of chains_sorted) { console.log(count, url); } + + console.log(stats); + } +} + +const write_results = async (stats, chains, format, outfile) => { + assert(outfile, "Output file required."); + + // unlike unix APIs this uses exceptions rather than return values for errors + const fd = fs.openSync(outfile, "w+"); + + if(format === "json") { + const data = {stats, chains, date: new Date()}; + const bytes = fs.writeSync(fd, Buffer.from(JSON.stringify(data, null, 4)), 0); + } else { + const chains_sorted = sort_request_chains(chains, OPTS.min); + + for(let [count, url] of chains_sorted) { + const bytes = fs.writeSync(fd, Buffer.from(`${count} ${url}\n`)); + } } - console.log(stats); + fs.closeSync(fd); } program @@ -272,6 +299,7 @@ program .option("--min ", "The lowest count to print. Stop at this.", 1) .option("--errors", "Show the erorrs so you can fix them.", false) .option("--format ", "Output format, text or json. Ignores min for raw output.", "json") + .option("--outfile ", "Save to file rather than stdout.") .requiredOption("--domain ", "Domain for the log. Gets removed as a refer.") .requiredOption("--input ", "Input file.") .description("Processes different web server logs to determine request chain frequency.") @@ -283,12 +311,16 @@ OPTS.min = parseInt(OPTS.min); assert(!isNaN(OPTS.min), `min must be a number, you have ${OPTS.min}`); -const [by_ip, stats] = await parse_logs(OPTS.input, OPTS.errors); -const chains = construct_request_chains(by_ip, OPTS.domain, OPTS.set); -const chains_sorted = sort_request_chains(chains); +try { + const [by_ip, stats] = await parse_logs(OPTS.input, OPTS.errors); + const chains = construct_request_chains(by_ip, OPTS.domain, OPTS.set); -if(OPTS.format === "json") { - console.log(chains); -} else { - output_results(chains_sorted, OPTS.min); + if(OPTS.outfile) { + write_results(stats, chains, OPTS.format, OPTS.outfile); + } else { + output_results(stats, chains, OPTS.format, OPTS.outfile); + } +} catch(error) { + console.error(error.message); + process.exit(1); }