Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

autocannon-reporter

Package Overview
Dependencies
Maintainers
2
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

autocannon-reporter - npm Package Compare versions

Comparing version 0.0.5 to 0.0.6

autocannon-banner.png

5

help.txt

@@ -9,2 +9,4 @@ Usage: autocannon-reporter [opts]

The path to the json results. Required when not piping into this tool.
-c/--compare FILES
The paths to multiple json results to be compared to the input.
-v/--version

@@ -14,1 +16,4 @@ Print the version number.

Print this menu.
You can also pipe in ndjson results, the first will be considered the input and
the rest are used for the comparison

65

index.js

@@ -8,5 +8,6 @@ #! /usr/bin/env node

const path = require('path')
const concat = require('concat-stream')
const buildReport = require('./template')
const help = fs.readFileSync(path.join(__dirname, 'help.txt'), 'utf8')
const ndjson = require('ndjson')
const steed = require('steed')

@@ -18,2 +19,3 @@ function start () {

input: 'i',
compare: 'c',
version: 'v',

@@ -26,7 +28,4 @@ help: 'h'

argv.outputPath = path.join(process.cwd(), 'report.html')
argv.outputPathFolder = path.dirname(argv.outputPath)
if (argv.version) {
console.log('autocannon', 'v' + require('./package').version)
console.log('autocannon-reporter', 'v' + require('./package').version)
console.log('node', process.version)

@@ -41,2 +40,9 @@ return

if (argv.compare) {
argv._.push(argv.compare)
argv.compare = argv._
}
argv.outputPath = path.join(process.cwd(), 'report.html')
argv.outputPathFolder = path.dirname(argv.outputPath)
if (process.stdin.isTTY) {

@@ -50,12 +56,14 @@ if (!argv.input) {

argv.inputPath = path.isAbsolute(argv.input) ? argv.input : path.join(process.cwd(), argv.input)
const results = require(argv.inputPath)
const report = buildReport(results)
writeReport(report, argv.outputPath, (err) => {
if (err) console.err('Error writting report: ', err)
else console.log('Report written to: ', argv.outputPath)
})
} else {
const concatStream = concat((res) => {
const results = JSON.parse(res.toString())
const report = buildReport(results)
argv.compare = argv.compare || []
steed.map(argv.compare, (val, cb) => {
val = path.isAbsolute(val) ? val : path.join(process.cwd(), val)
fs.access(val, fs.F_OK, function (err) {
if (err) return cb(new Error('Can\'t access ' + val))
cb(null, require(val))
})
}, (err, compare) => {
if (err) return console.log(err)
compare = sort(compare)
const results = require(argv.inputPath)
const report = buildReport(results, compare)
writeReport(report, argv.outputPath, (err) => {

@@ -66,3 +74,15 @@ if (err) console.err('Error writting report: ', err)

})
process.stdin.pipe(concatStream)
} else {
let compare = []
process.stdin
.pipe(ndjson.parse())
.on('data', (json) => { compare.push(json) })
.on('finish', () => {
compare = sort(compare)
const report = buildReport(compare[0], compare)
writeReport(report, argv.outputPath, (err) => {
if (err) console.err('Error writting report: ', err)
else console.log('Report written to: ', argv.outputPath)
})
})
}

@@ -81,1 +101,14 @@ }

}
function sort (array) {
array.sort(function (a, b) {
if (a.finish < b.finish) {
return 1
}
if (a.finish > b.finish) {
return -1
}
return 0
})
return array
}
{
"name": "autocannon-reporter",
"version": "0.0.5",
"version": "0.0.6",
"description": "A tool for creating html reports for autocannon",

@@ -42,3 +42,2 @@ "main": "index.js",

"dependencies": {
"concat-stream": "^1.5.1",
"flexboxgrid": "^6.3.0",

@@ -49,4 +48,6 @@ "hyperscript": "^1.4.7",

"moment": "^2.14.1",
"pretty-bytes": "^3.0.1"
"ndjson": "^1.4.3",
"pretty-bytes": "^3.0.1",
"steed": "^1.1.3"
}
}

@@ -0,3 +1,7 @@

![banner](autocannon-banner.png)
# Autocannon-reporter
[![Build Status](https://travis-ci.org/thekemkid/autocannon-reporter.svg?branch=master)](https://travis-ci.org/thekemkid/autocannon-reporter)
A simple html reporter for autocannon.

@@ -66,2 +70,4 @@

The path to the json results. Required when not piping into this tool.
-c/--compare FILES
The paths to multiple json results to be compared to the input.
-v/--version

@@ -71,2 +77,5 @@ Print the version number.

Print this menu.
You can also pipe in ndjson results, the first will be considered the input and
the rest are used for the comparison
```

@@ -76,7 +85,8 @@

#### buildReport(result)
#### buildReport(result, compare)
* `result`: The result of an autocannon run. `Object`. _Required_
* `compare`: An array of old autocannon results to compare against. `Array`. _optional_
Returns a string of html representing the results
Returns a string of html representing the results and comparison

@@ -90,11 +100,5 @@

## Todo
## Acknowledgements
- [ ] TESTS
- [ ] Pretty styling
- [ ] Generate pretty html for throughput and latency (use chartist?)
- [ ] Generate charts for throughput and latency
- [ ] Generate a bar chart for the reponse types (1xx, 2xx, 3xx, 4xx, 5xx)
- [ ] Pie chart, showing the amount of error, and how many of them were timeouts
- [ ] Possibly add the ability to enter multiple results and generate multiple reports on the same page, with comparisons between them?
Sponsored by [nearForm](http://www.nearform.com)

@@ -101,0 +105,0 @@ ## License

@@ -11,4 +11,11 @@ 'use strict'

module.exports = function (results) {
const bodyTree = report(results)
module.exports = function (results, compare) {
if (compare && compare.length > 0) {
for (let i = compare.length; i > 0; i--) {
if (compare[i - 1].start === results.start && compare[i - 1].finish === results.finish) {
compare.splice(i - 1, 1)
}
}
}
const bodyTree = report(results, compare)

@@ -33,3 +40,3 @@ const fullBody = `

<script>
${scripts(results)}
${scripts(results, compare)}
</script>

@@ -36,0 +43,0 @@ </body>

@@ -6,2 +6,4 @@ 'use strict'

const moment = require('moment')
const fs = require('fs')
const path = require('path')
function datestuff (date) {

@@ -12,11 +14,16 @@ return moment(date).format('MMMM Do YYYY, h:mm:ss a')

module.exports = function (results) {
module.exports = function (results, compare) {
const hx = hyperx(h)
return reportBody(results, hx, compare)
}
function reportBody (results, hx, compare) {
return hx`
<div>
<div class='title'>
${results.title ? hx`<h1>Results for ${results.title}</h1>` : hx`<h1>Autocannon results</h1>`}
<div class='header'>
<img class="logo" src="data:image/png;base64,${fs.readFileSync(path.join(__dirname, '../assets/autocannon-logo.png')).toString('base64')}"/>
${results.title ? hx`<h1>Results for ${results.title}</h1>` : hx`<h1>Results</h1>`}
</div>
<div class='report'>
<div class ='object content no-border'>
<div class ='object content no-border spaceout'>
<ul class ='grid'>

@@ -39,3 +46,4 @@ <li><b>Start Time:</b> ${datestuff(results.start)} </li>

</div>
${results['2xx'] + results.non2xx > 0 ? panels(results, hx) : warnPanel(results, hx)}
${results['2xx'] + results.non2xx > 0 ? panels(results, hx, compare) : warnPanel(results, hx)}
${compare && compare.length > 0 ? comparePanels(results, hx, compare) : ''}
</div>

@@ -46,8 +54,9 @@ </div>

function panels (results, hx) {
function panels (results, hx, compare) {
return hx`
<div class='panels'>
<div class='standard-panels'>
${responseBarPanel(results, hx)}
${responsePiePanel(results, hx)}
${latencyTablePanel(results, hx)}
${throughputTablePanel(results, hx)}
${results.errors === 0 && results.timeouts === 0 ? '' : errorPiePanel(results, hx)}
${tablesPanel(results, hx)}
</div>

@@ -57,25 +66,12 @@ `

function latencyTablePanel (results, hx) {
return hx`
<div class='object latency'>
function responseBarPanel (results, hx) {
return hx `
<div class='object responseBar'>
<div class='heading' onclick="growDiv(this)">
<h2 class='symbol'>-</h2>
<h2>Latency</h2>
<h2 class='symbol'>-</h2>
<h2>Response Times Histogram</h2>
</div>
<div class='content'>
<div class='content graph'>
<div class='measuringWrapper'>
<table class='table' style="width:100%">
<tr>
<th>Stat</th>
<th>Value</th>
</tr>
${
Object.keys(results.latency).map((key) => {
return hx`<tr>
<td>${key}</td>
<td>${results.latency[key]}</td>
</tr>`
})
}
</table>
<div class="ct-bar"></div>
</div>

@@ -87,25 +83,46 @@ </div>

function throughputTablePanel (results, hx) {
function responsePiePanel (results, hx) {
return hx `
<div class='object reponsePie'>
<div class='heading' onclick="growDiv(this)">
<h2 class='symbol'>-</h2>
<h2>Response Types Piechart</h2>
</div>
<div class='content graph'>
<div class='measuringWrapper'>
<div class="ct-chart-responses ct-perfect-fourth"></div>
</div>
</div>
</div>
`
}
function errorPiePanel (results, hx) {
return hx `
<div class='object errorPie'>
<div class='heading' onclick="growDiv(this)">
<h2 class='symbol'>-</h2>
<h2>Error Piechart</h2>
</div>
<div class='content graph'>
<div class='measuringWrapper'>
<div class="ct-error-pie ct-perfect-fourth"></div>
</div>
</div>
</div>
`
}
function tablesPanel (results, hx) {
return hx`
<div class='object throughput'>
<div class='object'>
<div class='heading' onclick="growDiv(this)">
<h2 class='symbol'>-</h2>
<h2>Throughput</h2>
<h2>Requests, Latency and Throughput</h2>
</div>
<div class='content'>
<div class='measuringWrapper'>
<table class='table' style="width:100%">
<tr>
<th>Stat</th>
<th>Value</th>
</tr>
${
Object.keys(results.throughput).map((key) => {
return hx`<tr>
<td>${key}</td>
<td>${prettyBytes(results.throughput[key])}</td>
</tr>`
})
}
</table>
<div class='measuringWrapper spaceout'>
${makeTable('Requests', results.latency, key => hx`<tr><td>${key}</td><td>${results.latency[key]}</td></tr>`)}
${makeTable('Latency', results.requests, key => hx`<tr><td>${key}</td><td>${results.requests[key]}</td></tr>`)}
${makeTable('Throughput', results.throughput, key => hx`<tr><td>${key}</td><td>${prettyBytes(results.throughput[key])}</td></tr>`)}
</div>

@@ -115,2 +132,15 @@ </div>

`
function makeTable (title, obj, map) {
return hx`
<div>
<h3>${title}</h3>
<table class='table' style="width:100%">
<tr>
<th>Stat</th>
<th>Value</th>
</tr>
${Object.keys(obj).map(map)}
</table>
</div>`
}
}

@@ -134,12 +164,23 @@

function responsePiePanel (results, hx) {
return hx `
<div class='object reponsePie'>
function comparePanels (results, hx, compare) {
return hx`
<div class='compare-panels'>
${requestsPanel(results, hx)}
${bandwidthPanel(results, hx)}
${latencyPanel(results, hx)}
${errorsPanel(results, hx)}
</div>
`
}
function requestsPanel (results, hx) {
return hx`
<div class='object requestsBar'>
<div class='heading' onclick="growDiv(this)">
<h2 class='symbol'>-</h2>
<h2>Response Types Piechart</h2>
<h2>Requests Comparison Chart</h2>
</div>
<div class='content graph'>
<div class='measuringWrapper'>
<div class="ct-chart ct-perfect-fourth"></div>
<div class="chart-request-linechart ct-perfect-fourth"></div>
</div>

@@ -150,1 +191,50 @@ </div>

}
function bandwidthPanel (results, hx) {
return hx`
<div class='object bandwidthBar'>
<div class='heading' onclick="growDiv(this)">
<h2 class='symbol'>-</h2>
<h2>Bandwidth Comparison Chart</h2>
</div>
<div class='content graph'>
<div class='measuringWrapper'>
<div class="chart-bandwidth-linechart ct-perfect-fourth"></div>
</div>
</div>
</div>
`
}
function latencyPanel (results, hx) {
return hx`
<div class='object latencyBar'>
<div class='heading' onclick="growDiv(this)">
<h2 class='symbol'>-</h2>
<h2>Latency Comparison Chart</h2>
</div>
<div class='content graph'>
<div class='measuringWrapper'>
<div class="chart-latency-linechart ct-perfect-fourth"></div>
</div>
</div>
</div>
`
}
function errorsPanel (results, hx) {
return hx`
<div class='object errorBar'>
<div class='heading' onclick="growDiv(this)">
<h2 class='symbol'>-</h2>
<h2>Error Comparison Chart</h2>
</div>
<div class='content graph'>
<div class='measuringWrapper'>
<div class='centeredText'><span class ='redText'>Red</span> = Errors, <span class='blueText'>Blue</span> = Timeouts</div>
<div class="chart-error-barchart ct-perfect-fourth"></div>
</div>
</div>
</div>
`
}
'use strict'
module.exports = function (results) {
module.exports = function (results, compare) {
return `
var results = ${JSON.stringify(results)}
var compare = ${JSON.stringify(compare)}
${prettyBytes.toString()}
${growDiv.toString()}
${main.toString()}
main(Chartist, results)
main(Chartist, results, compare)

@@ -14,36 +14,161 @@ `

function main (chartist, results) {
var labels = ['1xx', '2xx', '3xx', '4xx', '5xx', 'non2xx', 'timeouts']
function main (chartist, results, compare) {
var labels = ['1xx', '2xx', '3xx', '4xx', '5xx', 'timeouts']
var nonZeros = []
var seriesValues = []
labels.forEach(function (label) {
if (results[label] !== 0) {
nonZeros.push(label)
seriesValues.push(results[label])
}
})
var total = seriesValues.reduce(function (v, x) { return v + x }, 0)
var options = {
fullWidth: true,
height: 450,
labelInterpolationFnc: function (value) {
return value + ' (' + Math.round(results[value] / total * 100) + '%)'
}
}
chartist.Pie('.ct-chart-responses', {
labels: nonZeros,
series: seriesValues
}, options)
var errorLabels = []
var errorValues = []
if (results.errors !== 0) {
errorLabels.push('Errors (non-timeouts)')
errorValues.push(results.errors)
}
if (results.timeouts !== 0) {
errorLabels.push('Timeouts')
errorValues.push(results.timeouts)
}
chartist.Pie('.ct-error-pie', {
labels: errorLabels,
series: errorValues
}, {
fullWidth: true,
height: 450
})
var lineOptions = {
fullWidth: true,
height: 450,
axisY: {
offset: 70,
labelInterpolationFnc: function (value) {
return (value) + 'ms'
}
}
}
var responsiveOptions = [
['screen and (min-width: 640px)', {
chartPadding: 30,
labelOffset: 110,
labelDirection: 'explode',
var lineValues = [results.latency.min, results.latency.average,
results.latency.p50, results.latency.p75,
results.latency.p90, results.latency.p99, results.latency.p999, results.latency.p9999, results.latency.p99999]
chartist.Bar('.ct-bar', {
labels: ['min', 'average', '50%', '75%', '90%', '99%', '99.9%', '99.99%', '99.999%'],
series: [lineValues]
}, lineOptions)
// if compare array isn't used, return early
if (!compare) return
var requestOptions = {
fullWidth: true,
height: 450,
axisY: {
offset: 100,
labelInterpolationFnc: function (value) {
return value
return (value) + ' reqs/sec'
}
}],
['screen and (min-width: 1024px)', {
labelOffset: 90,
chartPadding: 20
}]
]
labels.forEach(function (label) {
if (results[label] !== 0) {
nonZeros.push(label)
},
low: 0
}
var compareRequestValues = []
var compareRequestLabels = []
compareRequestValues.push(results.requests.average)
compareRequestLabels.push(results.finish)
compare.forEach(function (value) {
compareRequestValues.push(value.requests.average)
compareRequestLabels.push(value.finish)
})
chartist.Line('.chart-request-linechart', {
labels: compareRequestLabels.reverse(),
series: [compareRequestValues.reverse()]
}, requestOptions)
var bandwidthOptions = {
fullWidth: true,
height: 450,
axisY: {
offset: 100,
labelInterpolationFnc: function (value) {
return prettyBytes(value) + '/sec'
}
},
low: 0
}
var compareBandwidthValues = []
var compareBandwidthLabels = []
compareBandwidthValues.push(results.requests.average)
compareBandwidthLabels.push(results.finish)
compare.forEach(function (value) {
compareBandwidthValues.push(value.requests.average)
compareBandwidthLabels.push(value.finish)
})
chartist.Line('.chart-bandwidth-linechart', {
labels: compareBandwidthLabels.reverse(),
series: [compareBandwidthValues.reverse()]
}, bandwidthOptions)
var latencyOptions = {
fullWidth: true,
height: 450,
axisY: {
offset: 100,
labelInterpolationFnc: function (value) {
return (Number(value).toPrecision(2) + ' ms')
}
},
low: 0
}
var compareLatencyValues = []
var compareLatencyLabels = []
compareLatencyValues.push(results.latency.average)
compareLatencyLabels.push(results.finish)
compare.forEach(function (value) {
compareLatencyValues.push(value.latency.average)
compareLatencyLabels.push(value.finish)
})
chartist.Line('.chart-latency-linechart', {
labels: compareLatencyLabels.reverse(),
series: [compareLatencyValues.reverse()]
}, latencyOptions)
var errorOptions = {
stackBars: true,
fullWidth: true,
height: 450,
chartPadding: {
left: 30
}
}
var compareErrorValues = []
var compareErrorLabels = []
var compareTimeoutValues = []
compareErrorValues.push(results.errors - results.timeouts)
compareTimeoutValues.push(results.timeouts)
compareErrorLabels.push(results.finish)
compare.forEach(function (value) {
compareErrorValues.push(value.errors - value.timeouts)
compareTimeoutValues.push(value.timeouts)
compareErrorLabels.push(value.finish)
})
nonZeros.forEach(function (value) {
seriesValues.push(results[value])
})
chartist.Pie('.ct-chart', {
labels: nonZeros,
series: seriesValues
}, options, responsiveOptions)
chartist.Bar('.chart-error-barchart', {
labels: compareErrorLabels.reverse(),
series: [compareTimeoutValues.reverse(), compareErrorValues.reverse()]
}, errorOptions)
}

@@ -56,10 +181,37 @@

var content = objectContainer.getElementsByClassName('content')[0]
if (content.clientHeight !== 20) {
var wrapper = content.getElementsByClassName('measuringWrapper')[0]
if (content.clientHeight > 20) {
content.style.height = 0
content.style.padding = '2px'
symbol.innerText = '+'
} else {
var wrapper = content.getElementsByClassName('measuringWrapper')[0]
content.style.height = wrapper.clientHeight + 'px'
content.style.padding = '20px'
symbol.innerText = '-'
}
}
function prettyBytes (num) {
if (typeof num !== 'number' || Number.isNaN(Number(num))) {
throw new TypeError('Expected a number, got ' + typeof num)
}
var exponent
var unit
var neg = num < 0
var units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
if (neg) {
num = -num
}
if (num < 1) {
return (neg ? '-' : '') + num + ' B'
}
exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), units.length - 1)
num = Number((num / Math.pow(1000, exponent)).toFixed(2))
unit = units[exponent]
return (neg ? '-' : '') + num + ' ' + unit
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc