UNPKG

parse-jtl

Version:
267 lines (235 loc) 9.71 kB
const path = require('path'); const fs = require("fs"); const csv_json = require('csvjson'); function parse(jtl_file_path) { const cwd = process.cwd(); const text = fs.readFileSync(path.join(cwd, jtl_file_path), { encoding: 'utf8' }); const rows = csv_json.toObject(text, { delimiter: ',', quote: '"' }); const aggregate_records = {}; const total_requests_record = getTotalRecord(); const total_transaction_record = getTotalRecord(); for (const record of rows) { parseRecord(record); if (!aggregate_records[record.label]) { setInitialAggregateReport(aggregate_records, record); } const total_report = aggregate_records[record.label].transaction ? total_transaction_record : total_requests_record; setCounts(aggregate_records, total_report, record); } summarize(aggregate_records); setSummaryCounts(total_requests_record); setSummaryCounts(total_transaction_record); copyLatencies(total_transaction_record, total_requests_record); return { requests: getFilteredRecord(aggregate_records, false), transactions: getFilteredRecord(aggregate_records, true), total_requests: total_requests_record, total_transactions: total_transaction_record, all: aggregate_records }; } function getTotalRecord() { return JSON.parse(JSON.stringify({ label: 'TOTAL', samples: 0, errors: 0, elapsed_times: [], max: Number.MIN_VALUE, min: Number.MAX_VALUE, total: 0, received: 0, sent: 0, latencies: [], max_latency: Number.MIN_VALUE, min_latency: Number.MAX_VALUE, total_latency: 0, })); } function parseRecord(record) { record.timeStamp = parseInt(record.timeStamp); record.elapsed = parseInt(record.elapsed); record.responseCode = parseInt(record.responseCode); record.bytes = parseInt(record.bytes); record.sentBytes = parseInt(record.sentBytes); if (record.Latency) { record.Latency = parseInt(record.Latency); } if (record.IdleTime) { record.IdleTime = parseInt(record.IdleTime); } if (record.Connect) { record.Connect = parseInt(record.Connect); } } function setInitialAggregateReport(aggregate_report, record) { aggregate_report[record.label] = { label: record.label, samples: 0, errors: 0, elapsed_times: [], max: Number.MIN_VALUE, min: Number.MAX_VALUE, total: 0, received: 0, sent: 0, start: record.timeStamp, transaction: record.URL === "null", latencies: [], max_latency: Number.MIN_VALUE, min_latency: Number.MAX_VALUE, total_latency: 0, }; } function setCounts(aggregate_records, total_report, record) { const aggregate_record = aggregate_records[record.label]; aggregate_record.samples += 1; total_report.samples += 1; if (record.responseCode >= 400) { aggregate_record.errors += 1; total_report.errors += 1; } aggregate_record.max = Math.max(aggregate_record.max, record.elapsed); total_report.max = Math.max(total_report.max, record.elapsed); aggregate_record.min = Math.min(aggregate_record.min, record.elapsed); total_report.min = Math.min(total_report.min, record.elapsed); aggregate_record.total += record.elapsed; total_report.total += record.elapsed; aggregate_record.received += record.bytes; total_report.received += record.bytes; aggregate_record.sent += record.sentBytes; total_report.sent += record.sentBytes; aggregate_record.elapsed_times.push(record.elapsed); total_report.elapsed_times.push(record.elapsed); aggregate_record.end = record.timeStamp + record.elapsed; total_report.end = record.timeStamp + record.elapsed; if (!total_report.start) { total_report.start = record.timeStamp; } if (Number.isInteger(record.Latency) && !aggregate_record.transaction) { aggregate_record.latencies.push(record.Latency); total_report.latencies.push(record.Latency); aggregate_record.max_latency = Math.max(aggregate_record.max_latency, record.Latency); total_report.max_latency = Math.max(total_report.max_latency, record.Latency); aggregate_record.min_latency = Math.min(aggregate_record.min_latency, record.Latency); total_report.min_latency = Math.min(total_report.min_latency, record.Latency); aggregate_record.total_latency += record.Latency; total_report.total_latency += record.Latency; } } function summarize(aggregate_report) { for (const key in aggregate_report) { if (Object.hasOwnProperty.call(aggregate_report, key)) { const transaction = aggregate_report[key]; setSummaryCounts(transaction); } } } function setSummaryCounts(total_record) { if (total_record.elapsed_times.length > 0) { total_record.tps = +((total_record.samples * 1000 / (total_record.end - total_record.start)).toFixed(2)); total_record.average = +((total_record.total / total_record.samples).toFixed(2)); const sorted_response_times = total_record.elapsed_times.sort((a, b) => b - a); total_record.p50 = calculatePercentile(sorted_response_times, 50); total_record.p90 = calculatePercentile(sorted_response_times, 90); total_record.p95 = calculatePercentile(sorted_response_times, 95); total_record.p99 = calculatePercentile(sorted_response_times, 99); total_record.error_rate = +((total_record.errors / total_record.samples).toFixed(2)); total_record.sent_rate = +((total_record.sent / (total_record.end - total_record.start)).toFixed(2)); total_record.received_rate = +((total_record.received / (total_record.end - total_record.start)).toFixed(2)); total_record.median = median(sorted_response_times); } else { total_record.max = 0; total_record.min = 0; } if (total_record.latencies.length > 0) { const sorted_latencies = total_record.latencies.sort((a, b) => b - a); total_record.average_latency = +((total_record.total_latency / total_record.samples).toFixed(2)); total_record.p50_latency = calculatePercentile(sorted_latencies, 50); total_record.p90_latency = calculatePercentile(sorted_latencies, 90); total_record.p95_latency = calculatePercentile(sorted_latencies, 95); total_record.p99_latency = calculatePercentile(sorted_latencies, 99); total_record.median_latency = median(sorted_latencies); } else { total_record.max_latency = 0; total_record.min_latency = 0; } } function calculatePercentile(sorted_response_times, percentile) { const divisor = (100 - percentile) / 100; const xPercent = parseInt(Math.ceil(sorted_response_times.length * divisor)); return sorted_response_times.slice(0, xPercent).slice(-1)[0]; }; function median(array) { if (array.length === 0) { return 0; } if (array.length % 2 !== 0) { return parseFloat(array[Math.floor(array.length / 2)]); } else { const mid = array.length / 2; return (array[mid - 1] + array[mid]) / 2; } } function getFilteredRecord(aggregate_report, transaction) { const filtered_report = {} for (const key in aggregate_report) { if (Object.hasOwnProperty.call(aggregate_report, key)) { const current_record = aggregate_report[key]; if (current_record['transaction'] === transaction) { filtered_report[key] = current_record; } } } return filtered_report; } function copyLatencies(total_transactions_record, total_requests_record) { if (total_requests_record.latencies.length > 0) { total_transactions_record.p50_latency = total_requests_record.p50_latency; total_transactions_record.p90_latency = total_requests_record.p90_latency; total_transactions_record.p95_latency = total_requests_record.p95_latency; total_transactions_record.p99_latency = total_requests_record.p99_latency; total_transactions_record.average_latency = total_requests_record.average_latency; total_transactions_record.median_latency = total_requests_record.median_latency; total_transactions_record.max_latency = total_requests_record.max_latency; total_transactions_record.min_latency = total_requests_record.min_latency; total_transactions_record.total_latency = total_requests_record.total_latency; total_transactions_record.latencies = total_requests_record.latencies; } } function aggregate(jtl_file_path) { const { total_transactions, transactions } = parse(jtl_file_path); const records = []; for (const key in transactions) { if (Object.hasOwnProperty.call(transactions, key)) { const transaction = transactions[key]; records.push(getCSVAggregateRecord(transaction)); } } records.push(getCSVAggregateRecord(total_transactions)); return records; } function getCSVAggregateRecord(aggregate_record) { const record = { 'Label': aggregate_record.label, '# Samples': aggregate_record.samples, 'Throughput': aggregate_record.tps, 'Average': aggregate_record.average, 'Median': aggregate_record.median, '90% Line': aggregate_record.p90, '95% Line': aggregate_record.p95, '99% Line': aggregate_record.p99, 'Min': aggregate_record.min, 'Max': aggregate_record.max, 'Error %': aggregate_record.error_rate + '%', 'Sent KB/sec': aggregate_record.sent_rate, 'Received KB/sec': aggregate_record.received_rate, } if (aggregate_record.latencies.length > 0) { record['Average Latency'] = aggregate_record.average_latency; record['Median Latency'] = aggregate_record.median_latency; record['90% Latency'] = aggregate_record.p90_latency; record['95% Latency'] = aggregate_record.p95_latency; record['99% Latency'] = aggregate_record.p99_latency; record['Min Latency'] = aggregate_record.min_latency; record['Max Latency'] = aggregate_record.max_latency; } return record; } module.exports = { parse, aggregate };