overload-protection
Advanced tools
Comparing version
@@ -20,3 +20,4 @@ 'use strict' | ||
maxRssBytes: 0, | ||
logging: false | ||
logging: false, | ||
logStatsOnReq: false | ||
} | ||
@@ -35,2 +36,5 @@ | ||
} | ||
if (opts.logStatsOnReq && opts.logging === false) { | ||
throw Error('logStatsOnReq cannot be enabled unless logging is also enabled') | ||
} | ||
var update = (opts.maxEventLoopDelay > 0) | ||
@@ -37,0 +41,0 @@ ? function update () { |
'use strict' | ||
var explain = require('./explain') | ||
var OverloadProtectionStats = require('./stats') | ||
Error.stackTraceLimit = Infinity | ||
module.exports = http | ||
@@ -12,2 +11,3 @@ | ||
var sendRetryHeader = clientRetrySecs > 0 | ||
var logStatsOnReq = opts.logStatsOnReq | ||
var logging = opts.logging | ||
@@ -23,2 +23,16 @@ var loggingOn = typeof logging === 'string' || typeof logging === 'function' | ||
function overloadProtection (req, res, next) { | ||
if (logStatsOnReq) { | ||
const stats = new OverloadProtectionStats( | ||
protect.overload, | ||
protect.eventLoopOverload, | ||
protect.heapUsedOverload, | ||
protect.rssOverload, | ||
protect.eventLoopDelay, | ||
protect.maxEventLoopDelay, | ||
protect.maxHeapUsedBytes, | ||
protect.maxRssBytes | ||
) | ||
if (log4jLogging) req.log && req.log[logging] && req.log[logging](stats) | ||
else logging(stats) | ||
} | ||
if (protect.overload === true) { | ||
@@ -25,0 +39,0 @@ res.statusCode = 503 |
@@ -5,2 +5,3 @@ 'use strict' | ||
var explain = require('./explain') | ||
var OverloadProtectionStats = require('./stats') | ||
@@ -10,2 +11,3 @@ function koa (opts, protect) { | ||
var sendRetryHeader = clientRetrySecs > 0 | ||
var logStatsOnReq = opts.logStatsOnReq | ||
var logging = opts.logging | ||
@@ -21,2 +23,16 @@ var loggingOn = typeof logging === 'string' || typeof logging === 'function' | ||
function overloadProtection (ctx, next) { | ||
if (logStatsOnReq) { | ||
const stats = new OverloadProtectionStats( | ||
protect.overload, | ||
protect.eventLoopOverload, | ||
protect.heapUsedOverload, | ||
protect.rssOverload, | ||
protect.eventLoopDelay, | ||
protect.maxEventLoopDelay, | ||
protect.maxHeapUsedBytes, | ||
protect.maxRssBytes | ||
) | ||
if (log4jLogging) ctx.log && ctx.log[logging] && ctx.log[logging](stats) | ||
else logging(stats) | ||
} | ||
if (protect.overload === true) { | ||
@@ -23,0 +39,0 @@ if (sendRetryHeader) ctx.set('Retry-After', clientRetrySecs) |
{ | ||
"name": "overload-protection", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"main": "index.js", | ||
@@ -38,8 +38,7 @@ "scripts": { | ||
"devDependencies": { | ||
"autocannon": "^0.16.5", | ||
"express": "^4.16.2", | ||
"koa": "^2.3.0", | ||
"koa-router": "^7.2.1", | ||
"express": "^4.17.1", | ||
"koa": "^2.11.0", | ||
"koa-router": "^7.4.0", | ||
"pre-commit": "^1.2.2", | ||
"restify": "^6.3.1", | ||
"restify": "^8.5.1", | ||
"standard": "^10.0.3", | ||
@@ -49,2 +48,3 @@ "tap": "^10.7.2" | ||
"dependencies": { | ||
"autocannon": "^4.4.1", | ||
"loopbench": "^1.2.0" | ||
@@ -51,0 +51,0 @@ }, |
@@ -43,2 +43,4 @@ # overload-protection | ||
// or propagate an error to the framework [default false] | ||
logging: false, // set to string for log level or function to pass data to | ||
logStatsOnReq: false // set to true to log stats on every requests | ||
} | ||
@@ -228,2 +230,7 @@ ``` | ||
#### logStatsOnReq: false | ||
Set `logStatsOnReq` to `true` log the profiled stats on every request. In order to use this option, the `logging` option must not be `false`. Bear in mind that using this option will | ||
add extra pressure on the event loop in itself, so use with caution. | ||
### instance.overload | ||
@@ -238,3 +245,3 @@ | ||
### profiler.eventLoopOverload | ||
### instance.eventLoopOverload | ||
@@ -248,3 +255,3 @@ The returned instance (which in many cases is passed as middleware to `app.use`), | ||
### profiler.heapUsedOverload | ||
### instance.heapUsedOverload | ||
@@ -258,3 +265,3 @@ The returned instance (which in many cases is passed as middleware to `app.use`), | ||
### profiler.rssOverload | ||
### instance.rssOverload | ||
@@ -261,0 +268,0 @@ The returned instance (which in many cases is passed as middleware to `app.use`), |
@@ -30,2 +30,11 @@ 'use strict' | ||
test('throws if logStatsOnReq is true but logging is false', function (t) { | ||
t.throws(function () { | ||
protect('http', { | ||
logStatsOnReq: true | ||
}) | ||
}) | ||
t.end() | ||
}) | ||
test('instance.stop ceases sampling', function (t) { | ||
@@ -32,0 +41,0 @@ var sI = global.setInterval |
@@ -540,1 +540,71 @@ 'use strict' | ||
}) | ||
test('if logStatsOnReq is true and if logging option is a string, writes log message using req.log as per level in string for every request', function (t) { | ||
var protect = protection('express', { | ||
logging: 'info', | ||
logStatsOnReq: true | ||
}) | ||
t.plan(1) | ||
var app = express() | ||
app.use(function (req, res, next) { | ||
req.log = { | ||
info: function (msg) { | ||
t.same(Object.keys(msg), [ | ||
'overload', | ||
'eventLoopOverload', | ||
'heapUsedOverload', | ||
'rssOverload', | ||
'eventLoopDelay', | ||
'maxEventLoopDelay', | ||
'maxHeapUsedBytes', | ||
'maxRssBytes' | ||
]) | ||
server.close() | ||
protect.stop() | ||
t.end() | ||
} | ||
} | ||
next() | ||
}) | ||
app.use(protect) | ||
app.get('/', function (req, res) { res.end('content') }) | ||
var server = http.createServer(app) | ||
server.listen(3000, function () { | ||
setTimeout(function () { | ||
http.get('http://localhost:3000').end() | ||
}, 6) | ||
}) | ||
}) | ||
test('if logStatsOnReq is true and logging option is a function, calls the function with stats on every request', function (t) { | ||
var protect = protection('express', { | ||
logStatsOnReq: true, | ||
logging: function (msg) { | ||
t.same(Object.keys(msg), [ | ||
'overload', | ||
'eventLoopOverload', | ||
'heapUsedOverload', | ||
'rssOverload', | ||
'eventLoopDelay', | ||
'maxEventLoopDelay', | ||
'maxHeapUsedBytes', | ||
'maxRssBytes' | ||
]) | ||
server.close() | ||
protect.stop() | ||
t.end() | ||
} | ||
}) | ||
var app = express() | ||
app.use(protect) | ||
app.get('/', function (req, res) { res.end('content') }) | ||
var server = http.createServer(app) | ||
server.listen(3001, function () { | ||
setTimeout(function () { | ||
http.get('http://localhost:3001').end() | ||
}, 6) | ||
}) | ||
}) |
@@ -591,1 +591,70 @@ 'use strict' | ||
}) | ||
test('if logStatsOnReq is true and if logging option is a string, writes log message using req.log as per level in string for every request', function (t) { | ||
var protect = protection('http', { | ||
logging: 'info', | ||
logStatsOnReq: true | ||
}) | ||
t.plan(1) | ||
var server = http.createServer(function serve (req, res) { | ||
req = { | ||
log: { | ||
info: function (msg) { | ||
t.same(Object.keys(msg), [ | ||
'overload', | ||
'eventLoopOverload', | ||
'heapUsedOverload', | ||
'rssOverload', | ||
'eventLoopDelay', | ||
'maxEventLoopDelay', | ||
'maxHeapUsedBytes', | ||
'maxRssBytes' | ||
]) | ||
server.close() | ||
protect.stop() | ||
t.end() | ||
} | ||
} | ||
} | ||
if (protect(req, res) === true) return | ||
res.end('content') | ||
}) | ||
server.listen(3000, function () { | ||
setTimeout(function () { | ||
http.get('http://localhost:3000').end() | ||
}, 6) | ||
}) | ||
}) | ||
test('if logStatsOnReq is true and logging option is a function, calls the function with stats on every request', function (t) { | ||
var protect = protection('http', { | ||
logStatsOnReq: true, | ||
logging: function (msg) { | ||
t.same(Object.keys(msg), [ | ||
'overload', | ||
'eventLoopOverload', | ||
'heapUsedOverload', | ||
'rssOverload', | ||
'eventLoopDelay', | ||
'maxEventLoopDelay', | ||
'maxHeapUsedBytes', | ||
'maxRssBytes' | ||
]) | ||
server.close() | ||
protect.stop() | ||
t.end() | ||
} | ||
}) | ||
var server = http.createServer(function serve (req, res) { | ||
if (protect(req, res) === true) return | ||
res.end('content') | ||
}) | ||
server.listen(3002, function () { | ||
setTimeout(function () { | ||
http.get('http://localhost:3002').end() | ||
}, 6) | ||
}) | ||
}) |
@@ -539,1 +539,67 @@ 'use strict' | ||
}) | ||
test('if logStatsOnReq is true and if logging option is a string, writes log message using req.log as per level in string for every request', function (t) { | ||
var protect = protection('koa', { | ||
logging: 'info', | ||
logStatsOnReq: true | ||
}) | ||
t.plan(1) | ||
var app = new Koa() | ||
app.use(function (ctx, next) { | ||
ctx.log = ctx.req.log = { | ||
info: function (msg) { | ||
t.same(Object.keys(msg), [ | ||
'overload', | ||
'eventLoopOverload', | ||
'heapUsedOverload', | ||
'rssOverload', | ||
'eventLoopDelay', | ||
'maxEventLoopDelay', | ||
'maxHeapUsedBytes', | ||
'maxRssBytes' | ||
]) | ||
server.close() | ||
protect.stop() | ||
t.end() | ||
} | ||
} | ||
return next() | ||
}) | ||
app.use(protect) | ||
var server = app.listen(3000, function () { | ||
setTimeout(function () { | ||
http.get('http://localhost:3000').end() | ||
}, 6) | ||
}) | ||
}) | ||
test('if logStatsOnReq is true and logging option is a function, calls the function with stats on every request', function (t) { | ||
var protect = protection('koa', { | ||
logStatsOnReq: true, | ||
logging: function (msg) { | ||
t.same(Object.keys(msg), [ | ||
'overload', | ||
'eventLoopOverload', | ||
'heapUsedOverload', | ||
'rssOverload', | ||
'eventLoopDelay', | ||
'maxEventLoopDelay', | ||
'maxHeapUsedBytes', | ||
'maxRssBytes' | ||
]) | ||
server.close() | ||
protect.stop() | ||
t.end() | ||
} | ||
}) | ||
var app = new Koa() | ||
app.use(protect) | ||
var server = app.listen(3001, function () { | ||
setTimeout(function () { | ||
http.get('http://localhost:3001').end() | ||
}, 6) | ||
}) | ||
}) |
@@ -534,1 +534,68 @@ 'use strict' | ||
}) | ||
test('if logStatsOnReq is true and if logging option is a string, writes log message using req.log as per level in string for every request', function (t) { | ||
var protect = protection('restify', { | ||
logging: 'info', | ||
logStatsOnReq: true | ||
}) | ||
t.plan(1) | ||
var server = restify.createServer({name: 'myapp', version: '1.0.0'}) | ||
server.use(function (req, res, next) { | ||
req.log = { | ||
info: function (msg) { | ||
t.same(Object.keys(msg), [ | ||
'overload', | ||
'eventLoopOverload', | ||
'heapUsedOverload', | ||
'rssOverload', | ||
'eventLoopDelay', | ||
'maxEventLoopDelay', | ||
'maxHeapUsedBytes', | ||
'maxRssBytes' | ||
]) | ||
server.close() | ||
protect.stop() | ||
t.end() | ||
} | ||
} | ||
next() | ||
}) | ||
server.use(protect) | ||
server.get('/', function (req, res) { res.end('content') }) | ||
server.listen(3000, function () { | ||
setTimeout(function () { | ||
http.get('http://localhost:3000').end() | ||
}, 6) | ||
}) | ||
}) | ||
test('if logStatsOnReq is true and logging option is a function, calls the function with stats on every request', function (t) { | ||
var protect = protection('restify', { | ||
logStatsOnReq: true, | ||
logging: function (msg) { | ||
t.same(Object.keys(msg), [ | ||
'overload', | ||
'eventLoopOverload', | ||
'heapUsedOverload', | ||
'rssOverload', | ||
'eventLoopDelay', | ||
'maxEventLoopDelay', | ||
'maxHeapUsedBytes', | ||
'maxRssBytes' | ||
]) | ||
server.close() | ||
protect.stop() | ||
t.end() | ||
} | ||
}) | ||
var server = restify.createServer({name: 'myapp', version: '1.0.0'}) | ||
server.use(protect) | ||
server.get('/', function (req, res) { res.end('content') }) | ||
server.listen(3001, function () { | ||
setTimeout(function () { | ||
http.get('http://localhost:3001').end() | ||
}, 6) | ||
}) | ||
}) |
102684
9.93%7
-12.5%32
3.23%3214
10.56%310
2.31%2
100%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added