mirror of
https://github.com/BreizhHardware/express-prom-bundle.git
synced 2026-01-19 00:37:36 +01:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e035e2b991 | ||
|
|
c6d5964768 | ||
|
|
94722e908b | ||
|
|
00b8369329 | ||
|
|
59221f891b | ||
|
|
3a0b2caf61 | ||
|
|
e7d004f0cc | ||
|
|
0dd3116f23 | ||
|
|
0606bf5f4f | ||
|
|
6054824c67 | ||
|
|
01c78bcc1d | ||
|
|
bc65dc45cb | ||
|
|
8cae5b6ef3 | ||
|
|
2003e7743f | ||
|
|
568c87216a | ||
|
|
98be36244e | ||
|
|
6ff1204db4 | ||
|
|
f71d837660 | ||
|
|
4aa2bfa6ae | ||
|
|
1fff877787 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
.npmrc
|
||||
node_modules
|
||||
coverage
|
||||
/.vscode
|
||||
|
||||
|
||||
@@ -2,3 +2,6 @@ language: node_js
|
||||
node_js:
|
||||
- "6"
|
||||
- "8"
|
||||
- "10"
|
||||
before_install:
|
||||
- npm install prom-client
|
||||
|
||||
35
README.md
35
README.md
@@ -4,17 +4,17 @@
|
||||
|
||||
Express middleware with popular prometheus metrics in one bundle. It's also compatible with koa v1 and v2 (see below).
|
||||
|
||||
Internally it uses **prom-client**. See: https://github.com/siimon/prom-client
|
||||
Since version 5 it uses **prom-client** as a peer dependency. See: https://github.com/siimon/prom-client
|
||||
|
||||
Included metrics:
|
||||
|
||||
* `up`: normally is just 1
|
||||
* `http_request_duration_seconds`: http latency histogram labeled with `status_code`, `method` and `path`
|
||||
* `http_request_duration_seconds`: http latency histogram/summary labeled with `status_code`, `method` and `path`
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install express-prom-bundle
|
||||
npm install prom-client express-prom-bundle
|
||||
```
|
||||
|
||||
## Sample Usage
|
||||
@@ -40,28 +40,6 @@ 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:
|
||||
@@ -71,6 +49,8 @@ Which labels to include in `http_request_duration_seconds` metric:
|
||||
* **includePath**: URL path (see importent details below), default: **false**
|
||||
* **customLabels**: an object containing extra labels, e.g. ```{project_name: 'hello_world'}```.
|
||||
Most useful together with **transformLabels** callback, otherwise it's better to use native Prometheus relabeling.
|
||||
* **includeUp**: include an auxiliary "up"-metric which always returns 1, default: **true**
|
||||
* **metricsPath**: replace the `/metrics` route with a **regex** or exact **string**. Note: it is highly recommended to just stick to the default
|
||||
|
||||
Extra transformation callbacks:
|
||||
|
||||
@@ -84,9 +64,14 @@ Extra transformation callbacks:
|
||||
* **formatStatusCode**: `function(res)` producing final status code from express `res` object, e.g. you can combine `200`, `201` and `204` to just `2xx`.
|
||||
* **transformLabels**: `function(labels, req, res)` transforms the **labels** object, e.g. setting dynamic values to **customLabels**
|
||||
|
||||
Metric type:
|
||||
|
||||
* **metricType**: two metric types are supported for `http_request_duration_seconds` metric: [histogram](https://prometheus.io/docs/concepts/metric_types/#histogram) and [summary](https://prometheus.io/docs/concepts/metric_types/#summary), default: **histogram**
|
||||
|
||||
Other options:
|
||||
|
||||
* **buckets**: buckets used for `http_request_duration_seconds` histogram
|
||||
* **percentiles**: percentiles used for `http_request_duration_seconds` summary
|
||||
* **autoregister**: if `/metrics` endpoint should be registered. (Default: **true**)
|
||||
* **promClient**: options for promClient startup, e.g. **collectDefaultMetrics**. This option was added
|
||||
to keep `express-prom-bundle` runnable using confit (e.g. with kraken.js) without writing any JS code,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
const promClient = require('prom-client');
|
||||
const promBundle = require('express-prom-bundle');
|
||||
|
||||
const bundle = promBundle({
|
||||
@@ -10,6 +11,7 @@ const bundle = promBundle({
|
||||
includePath: true,
|
||||
customLabels: {year: null},
|
||||
transformLabels: labels => Object.assign(labels, {year: new Date().getFullYear()}),
|
||||
metricsPath: '/prometheus',
|
||||
promClient: {
|
||||
collectDefaultMetrics: {
|
||||
timeout: 1000
|
||||
@@ -29,7 +31,7 @@ const bundle = promBundle({
|
||||
app.use(bundle);
|
||||
|
||||
// native prom-client metric (no prefix)
|
||||
const c1 = new bundle.promClient.Counter({name: 'c1', help: 'c1 help'});
|
||||
const c1 = new promClient.Counter({name: 'c1', help: 'c1 help'});
|
||||
c1.inc(10);
|
||||
|
||||
app.get('/foo/:id', (req, res) => {
|
||||
@@ -45,11 +47,13 @@ app.delete('/foo/:id', (req, res) => {
|
||||
app.get('/bar', (req, res) => res.send('bar response\n'));
|
||||
|
||||
app.listen(3000, () => console.info( // eslint-disable-line
|
||||
'listening on 3000\n'
|
||||
+ 'test in shell console\n\n'
|
||||
+ 'curl localhost:3000/foo/1234\n'
|
||||
+ 'curl localhost:3000/foo/09.08.2018\n'
|
||||
+ 'curl -X DELETE localhost:3000/foo/5432\n'
|
||||
+ 'curl localhost:3000/bar\n'
|
||||
+ 'curl localhost:3000/metrics\n'
|
||||
`listening on 3000
|
||||
test in shell console:
|
||||
|
||||
curl localhost:3000/foo/1234
|
||||
curl localhost:3000/foo/09.08.2018
|
||||
curl -X DELETE localhost:3000/foo/5432
|
||||
curl localhost:3000/bar
|
||||
curl localhost:3000/prometheus
|
||||
`
|
||||
));
|
||||
|
||||
1147
package-lock.json
generated
1147
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "express-prom-bundle",
|
||||
"version": "4.2.0",
|
||||
"version": "5.0.0",
|
||||
"description": "express middleware with popular prometheus metrics in one bundle",
|
||||
"main": "src/index.js",
|
||||
"keywords": [
|
||||
@@ -18,20 +18,22 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"on-finished": "^2.3.0",
|
||||
"prom-client": "~11.1.1",
|
||||
"url-value-parser": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^3.0.2",
|
||||
"eslint": "^5.3.0",
|
||||
"express": "^4.16.3",
|
||||
"eslint": "^5.11.0",
|
||||
"express": "^4.16.4",
|
||||
"istanbul": "^0.4.5",
|
||||
"jasme": "^5.2.0",
|
||||
"koa": "^2.5.2",
|
||||
"koa-connect": "^2.0.0",
|
||||
"supertest": "^3.0.0",
|
||||
"jasme": "^6.0.0",
|
||||
"koa": "^2.6.2",
|
||||
"koa-connect": "^2.0.1",
|
||||
"supertest": "^3.3.0",
|
||||
"supertest-koa-agent": "^0.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prom-client": "^11.1.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jochen-schweizer/express-prom-bundle.git"
|
||||
|
||||
@@ -18,7 +18,7 @@ describe('index', () => {
|
||||
it('metrics returns up=1', done => {
|
||||
const app = express();
|
||||
const bundled = bundle({
|
||||
whitelist: ['up']
|
||||
excludeRoutes: ['/irrelevant', /at.all/]
|
||||
});
|
||||
app.use(bundled);
|
||||
app.use('/test', (req, res) => res.send('it worked'));
|
||||
@@ -35,6 +35,64 @@ describe('index', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('"up"-metric can be excluded', done => {
|
||||
const app = express();
|
||||
const bundled = bundle({
|
||||
includeUp: false
|
||||
});
|
||||
app.use(bundled);
|
||||
app.use('/test', (req, res) => res.send('it worked'));
|
||||
|
||||
const agent = supertest(app);
|
||||
agent.get('/test').end(() => {
|
||||
agent
|
||||
.get('/metrics')
|
||||
.end((err, res) => {
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.text).not.toMatch(/up\s1/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('metrics path can be defined with a regex', done => {
|
||||
const app = express();
|
||||
const bundled = bundle({
|
||||
metricsPath: /^\/prometheus$/
|
||||
});
|
||||
app.use(bundled);
|
||||
app.use('/test', (req, res) => res.send('it worked'));
|
||||
|
||||
const agent = supertest(app);
|
||||
agent.get('/test').end(() => {
|
||||
agent
|
||||
.get('/prometheus')
|
||||
.end((err, res) => {
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.text).toMatch(/up\s1/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('metrics path can be defined as regexp', done => {
|
||||
const app = express();
|
||||
const bundled = bundle();
|
||||
app.use(bundled);
|
||||
app.use('/test', (req, res) => res.send('it worked'));
|
||||
|
||||
const agent = supertest(app);
|
||||
agent.get('/test').end(() => {
|
||||
agent
|
||||
.get('/metrics')
|
||||
.end((err, res) => {
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.text).toMatch(/up\s1/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('httpDurationMetricName overrides histogram metric name', done => {
|
||||
const app = express();
|
||||
const bundled = bundle({
|
||||
@@ -52,9 +110,7 @@ describe('index', () => {
|
||||
|
||||
it('metrics should be attached to /metrics by default', done => {
|
||||
const app = express();
|
||||
const bundled = bundle({
|
||||
whitelist: ['up']
|
||||
});
|
||||
const bundled = bundle();
|
||||
app.use(bundled);
|
||||
|
||||
const agent = supertest(app);
|
||||
@@ -83,27 +139,6 @@ describe('index', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('metrics can be filtered using exect match', () => {
|
||||
const instance = bundle({blacklist: ['up']});
|
||||
expect(instance.metrics.up).not.toBeDefined();
|
||||
expect(instance.metrics.http_request_duration_seconds).toBeDefined();
|
||||
});
|
||||
it('metrics can be filtered using regex', () => {
|
||||
const instance = bundle({blacklist: [/http/]});
|
||||
expect(instance.metrics.up).toBeDefined();
|
||||
expect(instance.metrics.http_request_duration_seconds).not.toBeDefined();
|
||||
});
|
||||
it('metrics can be whitelisted', () => {
|
||||
const instance = bundle({whitelist: [/^up$/]});
|
||||
expect(instance.metrics.up).toBeDefined();
|
||||
expect(instance.metrics.nodejs_memory_heap_total_bytes).not.toBeDefined();
|
||||
expect(instance.metrics.http_request_duration_seconds).not.toBeDefined();
|
||||
});
|
||||
it('throws on both white and blacklist', () => {
|
||||
expect(() => {
|
||||
bundle({whitelist: [/up/], blacklist: [/up/]});
|
||||
}).toThrow();
|
||||
});
|
||||
it('returns error 500 on incorrect middleware usage', done => {
|
||||
const app = express();
|
||||
app.use(bundle);
|
||||
@@ -140,22 +175,27 @@ describe('index', () => {
|
||||
it('filters out the excludeRoutes', done => {
|
||||
const app = express();
|
||||
const instance = bundle({
|
||||
excludeRoutes: ['/test']
|
||||
excludeRoutes: ['/test', /bad.word/]
|
||||
});
|
||||
app.use(instance);
|
||||
app.use('/test', (req, res) => res.send('it worked'));
|
||||
app.use('/some/bad-word', (req, res) => res.send('it worked too'));
|
||||
const agent = supertest(app);
|
||||
agent
|
||||
.get('/test')
|
||||
.end(() => {
|
||||
const metricHashMap = instance.metrics.http_request_duration_seconds.hashMap;
|
||||
expect(metricHashMap['status_code:200']).not.toBeDefined();
|
||||
|
||||
agent
|
||||
.get('/metrics')
|
||||
.end((err, res) => {
|
||||
expect(res.status).toBe(200);
|
||||
done();
|
||||
.get('/some/bad-word')
|
||||
.end(() => {
|
||||
const metricHashMap = instance.metrics.http_request_duration_seconds.hashMap;
|
||||
expect(metricHashMap['status_code:200']).not.toBeDefined();
|
||||
|
||||
agent
|
||||
.get('/metrics')
|
||||
.end((err, res) => {
|
||||
expect(res.status).toBe(200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -186,6 +226,33 @@ describe('index', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('metric type histogram works', done => {
|
||||
const app = express();
|
||||
const bundled = bundle({
|
||||
metricType: 'histogram',
|
||||
buckets: [10, 100],
|
||||
});
|
||||
app.use(bundled);
|
||||
app.use('/test', (req, res) => res.send('it worked'));
|
||||
|
||||
const agent = supertest(app);
|
||||
agent.get('/test').end(() => {
|
||||
agent
|
||||
.get('/metrics')
|
||||
.end((err, res) => {
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.text).toMatch(/le="100"/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('throws on unknown metricType ', () => {
|
||||
expect(() => {
|
||||
bundle({metricType: 'hello'});
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
describe('usage of normalizePath()', () => {
|
||||
|
||||
it('normalizePath can be replaced gloablly', done => {
|
||||
@@ -352,9 +419,7 @@ describe('index', () => {
|
||||
|
||||
it('Koa: metrics returns up=1', done => {
|
||||
const app = new Koa();
|
||||
const bundled = bundle({
|
||||
whitelist: ['up']
|
||||
});
|
||||
const bundled = bundle();
|
||||
app.use(c2k(bundled));
|
||||
|
||||
app.use(function(ctx, next) {
|
||||
@@ -420,4 +485,47 @@ describe('index', () => {
|
||||
});
|
||||
}, 6000);
|
||||
});
|
||||
|
||||
describe('metricType: summary', () => {
|
||||
it('metric type summary works', done => {
|
||||
const app = express();
|
||||
const bundled = bundle({
|
||||
metricType: 'summary'
|
||||
});
|
||||
app.use(bundled);
|
||||
app.use('/test', (req, res) => res.send('it worked'));
|
||||
|
||||
const agent = supertest(app);
|
||||
agent.get('/test').end(() => {
|
||||
agent
|
||||
.get('/metrics')
|
||||
.end((err, res) => {
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.text).toMatch(/quantile="0.98"/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('custom pecentiles work', done => {
|
||||
const app = express();
|
||||
const bundled = bundle({
|
||||
metricType: 'summary',
|
||||
percentiles: [0.5, 0.85, 0.99],
|
||||
});
|
||||
app.use(bundled);
|
||||
app.use('/test', (req, res) => res.send('it worked'));
|
||||
|
||||
const agent = supertest(app);
|
||||
agent.get('/test').end(() => {
|
||||
agent
|
||||
.get('/metrics')
|
||||
.end((err, res) => {
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.text).toMatch(/quantile="0.85"/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
173
src/index.js
173
src/index.js
@@ -1,11 +1,10 @@
|
||||
'use strict';
|
||||
const onFinished = require('on-finished');
|
||||
const promClient = require('prom-client');
|
||||
const normalizePath = require('./normalizePath');
|
||||
const normalizeStatusCode = require('./normalizeStatusCode');
|
||||
|
||||
function matchVsRegExps(element, regexps) {
|
||||
for (let regexp of regexps) {
|
||||
for (const regexp of regexps) {
|
||||
if (regexp instanceof RegExp) {
|
||||
if (element.match(regexp)) {
|
||||
return true;
|
||||
@@ -17,31 +16,10 @@ function matchVsRegExps(element, regexps) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function filterArrayByRegExps(array, regexps) {
|
||||
return array.filter(element => {
|
||||
return matchVsRegExps(element, regexps);
|
||||
});
|
||||
}
|
||||
|
||||
function prepareMetricNames(opts, metricTemplates) {
|
||||
const names = Object.keys(metricTemplates);
|
||||
if (opts.whitelist) {
|
||||
if (opts.blacklist) {
|
||||
throw new Error('you cannot have whitelist and blacklist at the same time');
|
||||
}
|
||||
return filterArrayByRegExps(names, opts.whitelist);
|
||||
}
|
||||
if (opts.blacklist) {
|
||||
const blacklisted = filterArrayByRegExps(names, opts.blacklist);
|
||||
return names.filter(name => blacklisted.indexOf(name) === -1);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
function clusterMetrics() {
|
||||
const aggregatorRegistry = new promClient.AggregatorRegistry();
|
||||
|
||||
const metricsMiddleware = function(req, res, next) {
|
||||
const metricsMiddleware = function(req, res) {
|
||||
aggregatorRegistry.clusterMetrics((err, clusterMetrics) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
@@ -56,16 +34,6 @@ function clusterMetrics() {
|
||||
}
|
||||
|
||||
function main(opts) {
|
||||
opts = Object.assign(
|
||||
{
|
||||
autoregister: true,
|
||||
includeStatusCode: true,
|
||||
normalizePath: main.normalizePath,
|
||||
formatStatusCode: main.normalizeStatusCode,
|
||||
promClient: {}
|
||||
},
|
||||
opts
|
||||
);
|
||||
if (arguments[2] && arguments[1] && arguments[1].send) {
|
||||
arguments[1].status(500)
|
||||
.send('<h1>500 Error</h1>\n'
|
||||
@@ -75,12 +43,27 @@ function main(opts) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (opts.prefix || opts.keepDefaultMetrics !== undefined) {
|
||||
opts = Object.assign(
|
||||
{
|
||||
autoregister: true,
|
||||
includeStatusCode: true,
|
||||
normalizePath: main.normalizePath,
|
||||
formatStatusCode: main.normalizeStatusCode,
|
||||
metricType: 'histogram',
|
||||
promClient: {}
|
||||
}, opts
|
||||
);
|
||||
|
||||
if (opts.prefix
|
||||
|| opts.keepDefaultMetrics !== undefined
|
||||
|| opts.whitelist !== undefined
|
||||
|| opts.blacklist !== undefined
|
||||
) {
|
||||
throw new Error(
|
||||
'express-prom-bundle detected obsolete options:'
|
||||
+ 'prefix and/or keepDefaultMetrics. '
|
||||
'express-prom-bundle detected one of the obsolete options: '
|
||||
+ 'prefix, keepDefaultMetrics, whitelist, blacklist. '
|
||||
+ 'Please refer to oficial docs. '
|
||||
+ 'Most likely you upgraded the module without necessary code changes'
|
||||
+ 'Most likely you upgraded the module without the necessary code changes'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,40 +73,46 @@ function main(opts) {
|
||||
|
||||
const httpMetricName = opts.httpDurationMetricName || 'http_request_duration_seconds';
|
||||
|
||||
const metricTemplates = {
|
||||
'up': () => new promClient.Gauge({
|
||||
name: 'up',
|
||||
help: '1 = up, 0 = not up'
|
||||
}),
|
||||
[httpMetricName]: () => {
|
||||
const labels = ['status_code'];
|
||||
if (opts.includeMethod) {
|
||||
labels.push('method');
|
||||
}
|
||||
if (opts.includePath) {
|
||||
labels.push('path');
|
||||
}
|
||||
if (opts.customLabels){
|
||||
labels.push.apply(labels, Object.keys(opts.customLabels));
|
||||
}
|
||||
const metric = new promClient.Histogram({
|
||||
function makeHttpMetric() {
|
||||
const labels = ['status_code'];
|
||||
if (opts.includeMethod) {
|
||||
labels.push('method');
|
||||
}
|
||||
if (opts.includePath) {
|
||||
labels.push('path');
|
||||
}
|
||||
if (opts.customLabels) {
|
||||
labels.push.apply(labels, Object.keys(opts.customLabels));
|
||||
}
|
||||
|
||||
if (opts.metricType === 'summary') {
|
||||
return new promClient.Summary({
|
||||
name: httpMetricName,
|
||||
help: 'duration summary of http responses labeled with: ' + labels.join(', '),
|
||||
labelNames: labels,
|
||||
percentiles: opts.percentiles || [0.5, 0.75, 0.95, 0.98, 0.99, 0.999]
|
||||
});
|
||||
} else if (opts.metricType === 'histogram' || !opts.metricType) {
|
||||
return new promClient.Histogram({
|
||||
name: httpMetricName,
|
||||
help: 'duration histogram of http responses labeled with: ' + labels.join(', '),
|
||||
labelNames: labels,
|
||||
buckets: opts.buckets || [0.003, 0.03, 0.1, 0.3, 1.5, 10]
|
||||
});
|
||||
return metric;
|
||||
} else {
|
||||
throw new Error('metricType option must be histogram or summary');
|
||||
}
|
||||
};
|
||||
|
||||
const metrics = {};
|
||||
const names = prepareMetricNames(opts, metricTemplates);
|
||||
|
||||
for (let name of names) {
|
||||
metrics[name] = metricTemplates[name]();
|
||||
}
|
||||
|
||||
if (metrics.up) {
|
||||
const metrics = {
|
||||
[httpMetricName]: makeHttpMetric()
|
||||
};
|
||||
|
||||
if (opts.includeUp !== false) {
|
||||
metrics.up = new promClient.Gauge({
|
||||
name: 'up',
|
||||
help: '1 = up, 0 = not up'
|
||||
});
|
||||
metrics.up.set(1);
|
||||
}
|
||||
|
||||
@@ -132,11 +121,13 @@ function main(opts) {
|
||||
res.end(promClient.register.metrics());
|
||||
};
|
||||
|
||||
const metricsMatch = opts.metricsPath instanceof RegExp ? opts.metricsPath
|
||||
: new RegExp('^' + (opts.metricsPath || '/metrics') + '/?$');
|
||||
|
||||
const middleware = function (req, res, next) {
|
||||
const path = req.originalUrl || req.url; // originalUrl gets lost in koa-connect?
|
||||
let labels;
|
||||
|
||||
if (opts.autoregister && path.match(/^\/metrics\/?$/)) {
|
||||
if (opts.autoregister && path.match(metricsMatch)) {
|
||||
return metricsMiddleware(req, res);
|
||||
}
|
||||
|
||||
@@ -144,42 +135,42 @@ function main(opts) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (metrics[httpMetricName]) {
|
||||
labels = {};
|
||||
let timer = metrics[httpMetricName].startTimer(labels);
|
||||
onFinished(res, () => {
|
||||
if (opts.includeStatusCode) {
|
||||
labels.status_code = opts.formatStatusCode(res, opts);
|
||||
}
|
||||
if (opts.includeMethod) {
|
||||
labels.method = req.method;
|
||||
}
|
||||
if (opts.includePath) {
|
||||
labels.path = typeof opts.normalizePath == 'function'
|
||||
? opts.normalizePath(req, opts)
|
||||
: main.normalizePath(req, opts);
|
||||
}
|
||||
if (opts.customLabels) {
|
||||
Object.assign(labels, opts.customLabels);
|
||||
}
|
||||
if (opts.transformLabels) {
|
||||
opts.transformLabels(labels, req, res);
|
||||
}
|
||||
timer();
|
||||
});
|
||||
}
|
||||
const labels = {};
|
||||
const timer = metrics[httpMetricName].startTimer(labels);
|
||||
|
||||
onFinished(res, () => {
|
||||
if (opts.includeStatusCode) {
|
||||
labels.status_code = opts.formatStatusCode(res, opts);
|
||||
}
|
||||
if (opts.includeMethod) {
|
||||
labels.method = req.method;
|
||||
}
|
||||
if (opts.includePath) {
|
||||
labels.path = opts.normalizePath instanceof Function
|
||||
? opts.normalizePath(req, opts)
|
||||
: main.normalizePath(req, opts);
|
||||
}
|
||||
if (opts.customLabels) {
|
||||
Object.assign(labels, opts.customLabels);
|
||||
}
|
||||
if (opts.transformLabels) {
|
||||
opts.transformLabels(labels, req, res);
|
||||
}
|
||||
timer();
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
middleware.metricTemplates = metricTemplates;
|
||||
middleware.metrics = metrics;
|
||||
middleware.promClient = promClient;
|
||||
middleware.metricsMiddleware = metricsMiddleware;
|
||||
return middleware;
|
||||
}
|
||||
|
||||
// this is kept only for compatibility with the code relying on older version
|
||||
main.promClient = promClient;
|
||||
|
||||
main.normalizePath = normalizePath;
|
||||
main.normalizeStatusCode = normalizeStatusCode;
|
||||
main.clusterMetrics = clusterMetrics;
|
||||
|
||||
Reference in New Issue
Block a user