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

logiload

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

logiload - npm Package Compare versions

Comparing version 0.0.2 to 0.0.3

a.txt

284

lib/runner.js

@@ -9,25 +9,31 @@ var async = require('async')

, Stats = require('./stats')
, agentId = 1
, csvFcty = require('./csv-output')
, agentId = 1
;
module.exports = fire;
module.exports = runner_run;
function fire(ctx, done) {
function runner_run(ctx, done) {
//TODO: validate ctx!!!
var macro = ctx
, total = ctx.total
, interval = ctx.interval
, expected = 0
, rid = 0
, lastSec = 0
, lastRPS = 0
, csv
, secIntr
var macro = ctx
, total = ctx.options.num
, arrivIntr = ctx.options.arriveInterval
, samplIntr = ctx.options.sampleInterval
, bail = !!ctx.options.bail
, rid = 0 //rid = request id
, sid = 0 //sid = step id
, lastRPS = 0 //Request Per Second
, csvStats
, csvReq
, secIntrv
;
ctx.agents = [];
ctx.byUrl = {};
csv = initCsvOutput(ctx);
//prepare stats bag per step
ctx.scenario.forEach(function(step) {
step.id = ++sid;
if (step.type != 'req') return;

@@ -37,38 +43,103 @@

//stats bag & rid per URL
//stats bag & rid per request-info
step.results = {};
step.req.forEach(function(req) {
req.id = ++rid;
req.stats = new Stats()
step.req.forEach(function(reqInfo) {
reqInfo.id = ++rid;
reqInfo.stats = new Stats();
if (!('bail' in reqInfo)) reqInfo.bail = bail;
})
});
macro.fired = 0;
macro.sec = lastSec = 0;
macro.starttime = Date.now();
macro.samples = [];
nextSample();
secIntr = setInterval(
function() {
log.info( "RPS:" , lastRPS = macro.fired );
csv.write( format("%s,%s\n", lastRPS, macro.sec) );
macro.fired = 0;
lastSec = macro.sec++
}
, 1000
);
macro.stats = newMacroStats();
macro.stats.started = 0;
macro.stats.expected = 0;
macro.stats.finished = 0;
macro.stats.returned = 0;
macro.sid = 0;
macro.starttime = new Date();
//init CSV output
csvReq =
csvFcty(
{ path : ctx.options.reqLog
, columns :
{ sid : "s-id"
, aid : "agent-id"
, step : "step-name"
, rid : "req-id-in-step"
, dur : "duration"
, statusCode: "status-code"
, error : "error"
, url : "url"
, starttime : "start-time"
, endtime : "end-time"
}
}
);
csvStats =
csvFcty(
{ path: ctx.options.statsLog
, columns:
{ sid : "sample-id" //macro.sample.sid
, reqPS : "Req/sec in sample" //macro.sample.fired / ( samplIntr / 1000 )
, retPS : "Ret/sec in sample" //macro.sample.returned / ( samplIntr / 1000 )
, sTime : "Req dur in sample" //macro.sample.avg
, errored : "Err in sample" //macro.sample.errored
, resTime : "Req dur" //macro.sample.avg
, users_conc : "conc. users" //macro.stats.expected ==>> macro.stats.started - macro.stats.finished
, reqcount : "conc. requests" //macro.stats.fired - macro.stats.returned
, smplstarted : "sent in sample" //macro.sample.started
, smpldone : "exitted in sample" //macro.sample.finished
, userstarted : "sent users" //macro.stats.started
, usersdone : "exitted users" //macro.stats.finished
, fired : "fired in sample" //macro.sample.fired
, returned : "returned in sample" //macro.sample.returned
, errorcount : "total req. err" //macro.stats.errored
, firecount : "total req. fired" //macro.stats.fired
, returncount : "total req. returned" //macro.stats.returned
}
}
);
macro.onRequest = function() {
macro.fired++;
macro.sample.fired++;
macro.stats.fired++;
}
macro.onResult = function(rslt) {
csv.write(
format(",%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n"
, macro.sec, rslt.aid, rslt.step, rslt.rid, rslt.dur, rslt.statusCode, rslt.url, rslt.error, rslt.starttime, rslt.endtime
)
)
macro.sample.returned++;
macro.stats.returned++;
macro.sample.gather(rslt.dur);
macro.stats.gather(rslt.dur);
rslt.sid = macro.sample.sid;
rslt.starttime /= 1000;
rslt.endtime /= 1000;
if (rslt.error) {
log.error("error", rslt);
//TODO - bail on unexpected errors
//OR - just count
macro.sample.errored++;
macro.stats.errored++;
}
csvReq.write( rslt );
}
secIntrv = setInterval(
function() {
dumpStatsRow();
nextSample();
}
, samplIntr
);
async.whilst(
async.whilst(
function() {

@@ -80,20 +151,3 @@ if (total)

}
, function(next) {
var agent =
run_user(ctx
, function() {
if (--expected)
return log.info("[a#%s] - finished. expecting %s more agents to finish", agent.id );
clearInterval(secIntr);
csv.end();
done()
}
)
;
ctx.agents.push( agent );
++expected;
setTimeout(next, interval)
}
, agent_start
, function(e) {

@@ -104,3 +158,88 @@ e

}
)
);
function agent_start(next) {
var agent = run_user(ctx
, function agent_finished(e) {
//TODO - check if to restart the user
//if (testDur && ) {
//}
if (--macro.stats.expected)
return log.info("[a#%s] - finished. expecting %s more agents to finish", agent.id );
cleanup(done);
}
);
setTimeout(next, arrivIntr)
}
//called upon interval
function dumpStatsRow(f) {
var s =
{ sid : macro.sample.sid || 0
, reqPS : macro.sample.fired / (samplIntr / 1000) || 0
, retPS : macro.sample.returned / (samplIntr / 1000) || 0
, sTime : macro.sample.avg || 0
, errored : macro.sample.errored || 0
, resTime : macro.stats.avg || 0
, users_conc : macro.stats.expected || 0
, reqcount : macro.stats.fired - macro.stats.returned || 0
, smplstarted : macro.sample.started || 0
, smpldone : macro.sample.finished || 0
, userstarted : macro.stats.started || 0
, usersdone : macro.stats.finished || 0
, fired : macro.sample.fired || 0
, returned : macro.sample.returned || 0
, errorcount : macro.stats.errored || 0
, firecount : macro.stats.fired || 0
, returncount : macro.stats.returned || 0
}
;
log.info("ReqPS: [%s], RetPS: [%s], avg Req. dur: [%s]", s.reqPS, s.retPS, s.sTime);
csvStats.write(s , f);
}
//called after last agent has finished scenario or bailed
function cleanup(done) {
log.info("cleanup...");
//clear interval
clearInterval(secIntrv);
//dump & close csvs
async.waterfall(
[ dumpStatsRow
, csvStats.end
, csvReq.end
]
, function(e) {
done(e, macro)
}
)
}
//creates a bag for the samples, and for the overal stats
function newMacroStats() {
return extend( new Stats(), {
fired : 0
, returned : 0
, started : 0
, finished : 0
, errored : 0
})
}
function nextSample() {
macro.sample = newMacroStats();
//TODO - skip keeping samples for very big tests
macro.samples.push(macro.sample);
macro.sample.sid = macro.samples.length;
}
}

@@ -113,8 +252,13 @@

, stats : new Stats()
, params : extend({}, macro.params)
, results: []
, params : extend({}, macro.options.params)
}
;
macro.agents.push(agent);
//on agent-start
++macro.stats.expected;
++macro.stats.started;
++macro.sample.started;
log.debug("[%s] - constructed", agent.id);5/7/2015
async.eachSeries( macro.scenario

@@ -149,2 +293,7 @@ , function(step, next) {

//on agent-finish
++macro.stats.finished;
++macro.sample.finished;
//TODO: count the brutally errored users
log[e?"error":"info"]( "[a#%s] - finished with %s, stats: ", agent.id, e ? e.message : "SUCCESS", stats);

@@ -157,17 +306,2 @@

return agent;
}
function initCsvOutput(ctx) {
var exists = fs.existsSync( ctx.csv )
, csv
;
csv = fs.createWriteStream(ctx.csv, {'flags': 'a'});
if (!exists)
csv.write("sec-id,RPS,agent-id,step-name,req-id-in-step,dur,status-code,url,hard-error,start-time,end-time\n");
else
log.warn("appending to an existing file: ", ctx.csv);
return csv
}

@@ -19,7 +19,14 @@ var LOG = require('log4js').getLogger('lib/steps/req')

log.debug("[a#%s] - entering step: " , aid, step.name);
log.info("[a#%s] - entering step: " , aid, step.name);
async.each( step.req
, function(reqInfo, next) {
var url = parameterize(agent.params, reqInfo.get)
//TODO: let the user provide req object, ready to fire with request
//TODO: add event hooks to measures
// - connect time - until connected
// - think time - from connected to accepting response headers
// - response time - from response headers to response end
var reqStats = reqInfo.stats
, url = parameterize(agent.params, reqInfo.get).replace(/,/g,"%2C")
, rslt =

@@ -34,8 +41,5 @@ { aid : aid

;
agent.results.push( rslt );
log.info("[a#%s] - firing: ", aid, url );
request(

@@ -50,4 +54,4 @@ { url : url

rslt.endtime = Date.now();
var reqStats = reqInfo.stats
, dur = rslt.dur = rslt.endtime - rslt.starttime
var dur = rslt.dur = rslt.endtime - rslt.starttime
, rej
;

@@ -59,3 +63,4 @@

if (e) {
rslt.error = e.name;
log.warn("request errored", e.message, reqInfo);
rslt.error = e.message;
rslt.statusCode = null;

@@ -68,14 +73,37 @@ }else{

log.info("[a#%s] - response [r#%s] arrived in [%sms] - ", aid, reqInfo.id, rslt.dur, e || "ok");
if ( reqInfo.expect && reqInfo.expect.code
&& r.statusCode != reqInfo.expectCode
) {
e =
{ message: "Wrong Status Code"
, expect : reqInfo.expect.code
, found : r.statusCode
}
}
log.info("[a#%s] - response [r#%s] arrived in [%sms] - ", aid, reqInfo.id, rslt.dur, e || r.statusCode);
log.info("req stats [r#%s]: %s", reqInfo.id, reqStats);
if ('function' == typeof reqInfo.onResponse) {
log.info("[a#%s] - runnig onResponse hook", aid);
log.info("[a#%s] - runnig onResponse hook:", aid, e ? e.message : "successfull request");
//TODO - exception safety + gather error when caught exception
reqInfo.onResponse.apply(ctx, [e, r]);
//TODO - move to event emittion
log.debug("[a#%s] - with", r ? r.body || "no body" : e);
try {
reqInfo.onResponse.apply(ctx, [e, r, rslt]);
} catch (ex) {
e = ex;
e.reqInfo = reqInfo;
e.reqUrl = url;
e.responseBody = (r || e).body;
e.httpCode = (r || e).statusCode;
log.error("req.onResponse",e);
}
}
//TODO - move to event emittion?
macro.onResult( rslt );
next(e)
next(reqInfo.bail ? e : null);
}

@@ -82,0 +110,0 @@ );

@@ -12,2 +12,3 @@ var LOG = require('log4js').getLogger('lib/steps/wait')

, aid = agent.id
, sleep = (step.wait || step.sleep) * rnd()
;

@@ -19,3 +20,5 @@

done()
}, step.sleep * 1000 );
}
}, sleep * 1000 );
}
function rnd() { return (Math.random() + Math.random() + Math.random()) / 1.5 }
{
"name": "logiload",
"version": "0.0.2",
"version": "0.0.3",
"description": "",
"main": "lib",
"bin" : {
"run" : "run.js"
"bin": {
"run": "bin/run"
},
"dependencies": {
"async": "~0.9.0",
"yargs": "~3.8.0",
"log4js": "~0.6.24",
"o-core": "0.0.5",
"request": "~2.55.0",
"log4js": "~0.6.24"
"yargs": "~3.8.0"
},

@@ -15,0 +16,0 @@ "devDependencies": {

logiload
==========
programmatic tool for load-testing in node-js for scenarios with heavy logic
programmatic tool for load-testing in node-js for scenarios with heavy logic.
Features overview
=================
*) url parameterization
*) any setting can be overriden usign CLI switches
*) patterned file-names
*) output request stat info into req.csv
*) output overview stats into stats.csv
url parameterization
---
TBD
any setting can be overriden usign CLI switches
---
TBD
Patterned file names
---
- %a - num of users (corresponds to CLI param -n,--num)
- %r - arrival interval (corresponds to CLI param -a,--arrive-interval)
- %p - sample interval (corresponds to CLI param -p,--sample-interval)
- %t - timestamp or timestamp+tag when tag is provided (tag corresponds to CLI param -t,--tag
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