healthchecks
Advanced tools
Comparing version 1.7.2 to 1.7.3
@@ -0,1 +1,6 @@ | ||
## Version 1.7.3 2016-06-21 | ||
CHANGED code cleanups and linting | ||
## Version 1.7.2 2015-12-15 | ||
@@ -2,0 +7,0 @@ |
@@ -0,1 +1,2 @@ | ||
/*eslint-disable */ | ||
// To run this example: | ||
@@ -2,0 +3,0 @@ // |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
// Exports an Express middleware factory. | ||
@@ -41,22 +42,28 @@ // | ||
// Represents a check outcome with the properties url, reason, etc. | ||
function Outcome(url, expected, error, statusCode, body, elapsed) { | ||
this.url = url; | ||
this.elapsed = hrTime(elapsed); | ||
if (error && error.code === 'ETIMEDOUT') { | ||
// | ||
// url - Checked URL | ||
// elapsed - In milliseconds | ||
// error - Protocol error | ||
// statusCode - HTTP status code | ||
// body - Response body | ||
// expected - Expected response body (array) | ||
function Outcome(args) { | ||
this.url = args.url; | ||
this.elapsed = hrTime(args.elapsed); | ||
if (args.error && args.error.code === 'ETIMEDOUT') { | ||
this.reason = 'timeout'; | ||
this.timeout = true; | ||
} else if (error) { | ||
} else if (args.error) { | ||
this.reason = 'error'; | ||
this.error = error; | ||
this.error = args.error; | ||
} else { | ||
this.statusCode = statusCode; | ||
this.body = body; | ||
if (statusCode < 200 || statusCode >= 400) | ||
this.statusCode = args.statusCode; | ||
this.body = args.body; | ||
if (this.statusCode < 200 || this.statusCode >= 400) | ||
this.reason = 'statusCode'; | ||
else { | ||
const allMatching = expected.every(function(text) { | ||
return ~body.indexOf(text); | ||
}); | ||
const expected = args.expected; | ||
const allMatching = expected.every(text => ~args.body.indexOf(text)); | ||
if (!allMatching) | ||
@@ -89,2 +96,3 @@ this.reason = 'body'; | ||
} | ||
// no default | ||
} | ||
@@ -98,6 +106,6 @@ }; | ||
case 'error': { | ||
return this.url + ' => ' + this.error.message; | ||
return `${this.url} => ${this.error.message}`; | ||
} | ||
case 'statusCode': { | ||
return this.url + ' => ' + this.statusCode; | ||
return `${this.url} => ${this.statusCode}`; | ||
} | ||
@@ -109,3 +117,3 @@ case undefined: { | ||
default: { | ||
return this.url + ' => ' + this.reason; | ||
return `${this.url} => ${this.reason}`; | ||
} | ||
@@ -123,3 +131,9 @@ } | ||
// the resolver function. | ||
function runCheck(url, headers, resolver, timeout, redirects) { | ||
function runCheck(args) { | ||
const url = args.url; | ||
const headers = args.headers; | ||
const resolver = args.resolver; | ||
const timeout = args.timeout; | ||
const redirects = args.redirects || 0; | ||
const loopbackURL = resolver(url); | ||
@@ -136,21 +150,22 @@ const request = { | ||
return new Promise(function(resolve, reject) { | ||
redirects = redirects || 0; | ||
get(request, timeout) | ||
.then(function(res) { | ||
if (~REDIRECT_STATUSES.indexOf(res.statusCode)) { | ||
if (redirects < MAX_REDIRECT_COUNT) { | ||
const redirectURL = resolver(res.headers.location); | ||
if (withinSameDomain(redirectURL, loopbackURL)) | ||
runCheck(res.headers.location, headers, resolver, timeout, redirects + 1) | ||
.then(resolve, reject); | ||
else | ||
resolve(res); | ||
} else | ||
reject(new Error('too many redirects')); | ||
} else | ||
resolve(res); | ||
}) | ||
.catch(reject); | ||
}); | ||
return get(request, timeout) | ||
.then(function(response) { | ||
const isRedirect = ~REDIRECT_STATUSES.indexOf(response.statusCode); | ||
if (isRedirect) { | ||
const redirectLoop = redirects >= MAX_REDIRECT_COUNT; | ||
if (redirectLoop) | ||
throw new Error('too many redirects'); | ||
else { | ||
const redirectURL = response.headers.location; | ||
const sameDomain = withinSameDomain(resolver(redirectURL), loopbackURL); | ||
if (sameDomain) | ||
return runCheck({ url: redirectURL, headers, resolver, timeout, redirects: redirects + 1 }); | ||
else | ||
return response; | ||
} | ||
} else | ||
return response; | ||
}); | ||
} | ||
@@ -205,3 +220,7 @@ | ||
// failed - A list of all check URLs that failed | ||
function checkFunction(protocol, hostname, port, requestID, strictSSL) { | ||
function checkFunction(url, requestID) { | ||
const protocol = URL.parse(url).protocol; | ||
const hostname = URL.parse(url).hostname; | ||
const port = URL.parse(url).port; | ||
const checks = this.checks; | ||
@@ -214,3 +233,3 @@ const timeout = this.timeout; | ||
function loopbackResolve(relativeURL) { | ||
const absoluteURL = URL.parse(URL.resolve(protocol + '://localhost/', relativeURL)); | ||
const absoluteURL = URL.parse(URL.resolve(`${protocol}//localhost/`, relativeURL)); | ||
const loopbackURL = Object.assign({}, absoluteURL, { | ||
@@ -228,22 +247,22 @@ hostname: absoluteURL.hostname, | ||
return new Promise(function(resolve) { | ||
// We need to make an HTTP/S request to the current server, | ||
// based on the hostname/port passed to us, | ||
// so the HTTP check would go to http://localhost:80/ or some such URL. | ||
const headers = { | ||
'User-Agent': 'Mozilla/5.0 (compatible) Healthchecks http://broadly.com', | ||
'X-Request-Id': requestID || '' | ||
}; | ||
// We need to make an HTTP/S request to the current server, | ||
// based on the hostname/port passed to us, | ||
// so the HTTP check would go to http://localhost:80/ or some such URL. | ||
const headers = { | ||
'User-Agent': 'Mozilla/5.0 (compatible) Healthchecks http://broadly.com', | ||
'X-Request-Id': requestID || '' | ||
}; | ||
const start = process.hrtime(); | ||
runCheck(checkURL, headers, loopbackResolve, timeout) | ||
.then(function(res) { | ||
const elapsed = process.hrtime(start); | ||
resolve(new Outcome(checkURL, expected, null, res.statusCode, res.body, elapsed)); | ||
}) | ||
.catch(function(error) { | ||
const elapsed = process.hrtime(start); | ||
resolve(new Outcome(checkURL, expected, error, null, null, elapsed)); | ||
}); | ||
}); | ||
const start = process.hrtime(); | ||
return runCheck({ url: checkURL, headers, resolver: loopbackResolve, timeout }) | ||
.then(function(response) { | ||
const elapsed = process.hrtime(start); | ||
const outcome = new Outcome({ url: checkURL, expected, statusCode: response.statusCode, body: response.body, elapsed }); | ||
return outcome; | ||
}) | ||
.catch(function(error) { | ||
const elapsed = process.hrtime(start); | ||
const outcome = new Outcome({ url: checkURL, expected, error, elapsed }); | ||
return outcome; | ||
}); | ||
}); | ||
@@ -259,4 +278,4 @@ | ||
return { | ||
passed: outcomes.filter(function(outcome) { return !outcome.reason; }), | ||
failed: outcomes.filter(function(outcome) { return outcome.reason; }) | ||
passed: outcomes.filter(outcome => !outcome.reason ), | ||
failed: outcomes.filter(outcome => outcome.reason ) | ||
}; | ||
@@ -273,18 +292,9 @@ }); | ||
const checks = File.readFileSync(filename, 'utf-8') | ||
.split(/[\n\r]+/) // Split into lines | ||
.map(function(line) { // Ignore leading/trailing spaces | ||
return line.trim(); | ||
}) | ||
.filter(function(line) { // Ignore empty lines | ||
return line.length; | ||
}) | ||
.filter(function(line) { // Ignore comments | ||
return line[0] !== '#'; | ||
}) | ||
.filter(function(line) { // Ignore name = value pairs | ||
return !/^\w+=/.test(line); | ||
}) | ||
.split(/[\n\r]+/) // Split into lines | ||
.map(line => line.trim()) // Ignore leading/trailing spaces | ||
.filter(line => line.length) // Ignore empty lines | ||
.filter(line => line[0] !== '#') // Ignore comments | ||
.filter(line => !/^\w+=/.test(line)) // Ignore name = value pairs | ||
.map(function(line) { // Split line to URL + expected value | ||
const match = line.match(/^(\S+)\s*(.*)/); | ||
//debug('Added check %s %s', match[1], match[2]); | ||
return { | ||
@@ -303,4 +313,4 @@ url: match[1], | ||
.reduce(function(memo, check) { | ||
const url = check.url; | ||
memo[url] = memo[url] || []; | ||
const url = check.url; | ||
memo[url] = memo[url] || []; // eslint-disable-line | ||
if (check.expected) | ||
@@ -321,4 +331,5 @@ memo[url].push(check.expected); | ||
// Returns a comparer function suitable for Array.sort(). | ||
function compare(propName) { | ||
function compareProperty(propName) { | ||
return function(a, b) { | ||
@@ -333,2 +344,18 @@ if (a[propName] < b[propName]) | ||
// Respond with 200 only if all checks passed | ||
// Respond with 500 if any check fail | ||
// Respond with 404 if there are no checks to run | ||
function statusCodeFromOutcomes(passed, failed) { | ||
const anyFailed = failed.length > 0; | ||
const anyPassed = passed.length > 0; | ||
if (anyFailed) | ||
return 500; | ||
else if (anyPassed) | ||
return 200; | ||
else | ||
return 404; | ||
} | ||
// Call this function to configure and return the middleware. | ||
@@ -339,12 +366,11 @@ module.exports = function healthchecks(options) { | ||
// Pass filename as first argument or named option | ||
const filename = typeof(options) === 'string' ? options : options.filename; | ||
const filename = typeof (options) === 'string' ? options : options.filename; | ||
assert(filename, 'Missing checks filename'); | ||
// Pass timeout as named option, or use default | ||
const timeoutArg = (typeof(options) === 'object' && options.timeout) || DEFAULT_TIMEOUT; | ||
const timeoutArg = (typeof (options) === 'object' && options.timeout) || DEFAULT_TIMEOUT; | ||
// If timeout argument is a string (e.g. "3d"), convert to milliseconds | ||
const timeout = (typeof(timeoutArg) === 'string') ? ms(timeoutArg) : + timeoutArg; | ||
const timeout = (typeof (timeoutArg) === 'string') ? ms(timeoutArg) : parseInt(timeoutArg, 10); | ||
const onFailed = options.onFailed || function() {}; | ||
const strictSSL = options.strictSSL === false ? false : true; | ||
@@ -358,2 +384,3 @@ // Read all checks form the file and returns a checking function | ||
// Return the Express middleware | ||
@@ -367,23 +394,18 @@ return function(req, res) { | ||
// 127.0.0.1:5000 | ||
const protocol = req.socket.encrypted ? 'https' : 'http'; | ||
const protocol = req.socket.encrypted ? 'https:' : 'http:'; | ||
const hostname = req.socket.localAddress; | ||
const port = req.socket.localPort; | ||
const url = URL.format({ protocol, hostname, port }); | ||
// Run all checks | ||
debug('Running against %s://%s:%d with request-ID %s', protocol, hostname, port, requestID); | ||
runChecks(protocol, hostname, port, requestID, strictSSL) | ||
runChecks(url, requestID) | ||
.then(function(outcomes) { | ||
debug('%d passed and %d failed', outcomes.passed.length, outcomes.failed.length); | ||
// Respond with 200 only if all checks passed | ||
// Respond with 500 if any check fail | ||
// Respond with 404 if there are no checks to run | ||
const statusCode = | ||
outcomes.failed.length ? 500 : | ||
outcomes.passed.length ? 200 : 404; | ||
// Render template | ||
const html = render({ | ||
passed: outcomes.passed.sort(compare('url')), | ||
failed: outcomes.failed.sort(compare('url')) | ||
}); | ||
const passed = outcomes.passed.sort(compareProperty('url')); | ||
const failed = outcomes.failed.sort(compareProperty('url')); | ||
const statusCode = statusCodeFromOutcomes(passed, failed); | ||
const html = render({ passed, failed }); | ||
res.writeHeader(statusCode); | ||
@@ -393,4 +415,4 @@ res.write(html); | ||
if (outcomes.failed.length) | ||
onFailed(outcomes.failed); | ||
if (failed.length > 0) | ||
onFailed(failed); | ||
}); | ||
@@ -400,1 +422,3 @@ }; | ||
}; | ||
{ | ||
"name": "healthchecks", | ||
"version": "1.7.2", | ||
"version": "1.7.3", | ||
"engines": { | ||
@@ -8,3 +8,4 @@ "node": ">=4.0.0" | ||
"scripts": { | ||
"test": "mocha" | ||
"lint": "eslint .", | ||
"test": "mocha && npm run lint" | ||
}, | ||
@@ -14,10 +15,10 @@ "main": "lib/healthchecks", | ||
"debug": "^2.2.0", | ||
"handlebars": "^3.0", | ||
"handlebars": "^4.0.5", | ||
"ms": "^0.7.1", | ||
"pretty-hrtime": "^1.0.0" | ||
"pretty-hrtime": "^1.0.2" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^0.21", | ||
"eslint": "^1.10.3", | ||
"express": "^4.12", | ||
"mocha": "^2.2", | ||
"mocha": "^2.3.4", | ||
"request": "^2.67.0", | ||
@@ -24,0 +25,0 @@ "zombie": "^4.0" |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
const assert = require('assert'); | ||
@@ -20,3 +21,3 @@ const healthchecks = require('..'); | ||
assert.equal(response.statusCode, 404); | ||
done(); | ||
done(error); | ||
}); | ||
@@ -23,0 +24,0 @@ }); |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
const express = require('express'); | ||
@@ -15,7 +16,7 @@ const healthchecks = require('../..'); | ||
// server is ready to receive requests. Server only started once. | ||
var listening = false; | ||
let listening = false; | ||
server.ready = function(callback) { | ||
if (listening) | ||
setImmediate(callback); | ||
else | ||
else { | ||
server.listen(3000, function() { | ||
@@ -25,2 +26,3 @@ listening = true; | ||
}); | ||
} | ||
}; | ||
@@ -27,0 +29,0 @@ |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
const assert = require('assert'); | ||
@@ -2,0 +3,0 @@ const ms = require('ms'); |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
const assert = require('assert'); | ||
@@ -22,3 +23,3 @@ const ms = require('ms'); | ||
assert.equal(response.statusCode, 200); | ||
done(); | ||
done(error); | ||
}); | ||
@@ -37,3 +38,3 @@ }); | ||
assert.equal(response.statusCode, 500); | ||
done(); | ||
done(error); | ||
}); | ||
@@ -58,3 +59,3 @@ }); | ||
assert.equal(response.statusCode, 500); | ||
done(); | ||
done(error); | ||
}); | ||
@@ -77,3 +78,3 @@ }); | ||
assert.equal(response.statusCode, 500); | ||
done(); | ||
done(error); | ||
}); | ||
@@ -96,3 +97,3 @@ }); | ||
assert.equal(response.statusCode, 500); | ||
done(); | ||
done(error); | ||
}); | ||
@@ -115,3 +116,3 @@ }); | ||
assert.equal(response.statusCode, 500); | ||
done(); | ||
done(error); | ||
}); | ||
@@ -118,0 +119,0 @@ }); |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
const Browser = require('zombie'); | ||
@@ -2,0 +3,0 @@ const ms = require('ms'); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
50502
24
1021
+ Addedhandlebars@4.7.8(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedneo-async@2.6.2(transitive)
+ Addedsource-map@0.6.1(transitive)
+ Addeduglify-js@3.19.3(transitive)
+ Addedwordwrap@1.0.0(transitive)
- Removedalign-text@0.1.4(transitive)
- Removedamdefine@1.0.1(transitive)
- Removedcamelcase@1.2.1(transitive)
- Removedcenter-align@0.1.3(transitive)
- Removedcliui@2.1.0(transitive)
- Removeddecamelize@1.2.0(transitive)
- Removedhandlebars@3.0.8(transitive)
- Removedis-buffer@1.1.6(transitive)
- Removedkind-of@3.2.2(transitive)
- Removedlazy-cache@1.0.4(transitive)
- Removedlongest@1.0.1(transitive)
- Removedminimist@0.0.10(transitive)
- Removedoptimist@0.6.1(transitive)
- Removedrepeat-string@1.6.1(transitive)
- Removedright-align@0.1.3(transitive)
- Removedsource-map@0.1.430.5.7(transitive)
- Removeduglify-js@2.8.29(transitive)
- Removeduglify-to-browserify@1.0.2(transitive)
- Removedwindow-size@0.1.0(transitive)
- Removedwordwrap@0.0.20.0.3(transitive)
- Removedyargs@3.10.0(transitive)
Updatedhandlebars@^4.0.5
Updatedpretty-hrtime@^1.0.2