Add support for clusterMaster option re: #16 (#17)

* Add support for clusterMaster option re: #16
* Add Cluster instructions to README
* Use the approach recommended in PR
* use console.error for errors
* Update with new method signature
* add code coverage for new clusterMetrics middleware
This commit is contained in:
Adam Yost
2018-08-24 17:36:23 -04:00
committed by Konstantin Pogorelov
parent 5e0cd75673
commit 02fcda4721
5 changed files with 446 additions and 389 deletions

View File

@@ -40,6 +40,28 @@ The order in which the routes are registered is important, since
You can use this to your advantage to bypass some of the routes.
See the example below.
## Usage with Node Cluster
``` javascript
if (cluster.isMaster) {
const numCPUs = Math.max(2, os.cpus().length);
const workers: cluster.Worker[] = [];
for (let i=1; i < numCPUs; i++) {
const worker = forkWorker();
workers.push(worker);
}
const metricsApp = express();
metricsApp.use('/cluster_metrics', promBundle.clusterMetrics());
metricsApp.listen(9999);
console.log('metrics listening on 9999'); // call localhost:9999/cluster_metrics for aggregated metrics
} else {
const app = express();
app.use(promBundle({includeMethod: true});
app.use('/api', require('./api'));
app.listen(3000);
}
```
The code the master process runs will expose an API with a single endpoint `/cluster_metrics` which returns an aggregate of all metrics from all the workers.
## Options
Which labels to include in `http_request_duration_seconds` metric:

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "express-prom-bundle",
"version": "4.0.0",
"version": "4.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -11,7 +11,7 @@
"method"
],
"scripts": {
"test": "node_modules/jasme/run.js"
"test": "jasme"
},
"author": "Konstantin Pogorelov <or@pluseq.com>",
"license": "MIT",

View File

@@ -259,6 +259,20 @@ describe('index', () => {
});
});
describe('usage of clusterMetrics()', () => {
it('clusterMetrics returns metrics for aggregator', (done) => {
const app = express();
app.use('/cluster_metrics', bundle.clusterMetrics());
const agent = supertest(app);
agent
.get('/metrics_cluster')
.expect(200)
.end((err, res) => {
done(err);
});
});
});
it('formatStatusCode can be overridden', done => {
const app = express();
const instance = bundle({

View File

@@ -38,6 +38,26 @@ function prepareMetricNames(opts, metricTemplates) {
return names;
}
function clusterMetrics() {
const aggregatorRegistry = new promClient.AggregatorRegistry();
const metricsMiddleware = function(req, res, next) {
if (aggregatorRegistry) {
aggregatorRegistry.clusterMetrics((err, clusterMetrics) => {
if (err) {
console.error(err);
}
res.set('Content-Type', aggregatorRegistry.contentType);
res.send(clusterMetrics);
});
} else {
return next();
}
};
return metricsMiddleware;
}
function main(opts) {
opts = Object.assign(
{
@@ -165,4 +185,5 @@ function main(opts) {
main.promClient = promClient;
main.normalizePath = normalizePath;
main.normalizeStatusCode = normalizeStatusCode;
main.clusterMetrics = clusterMetrics;
module.exports = main;