Compare commits

...

14 Commits
6.2.0 ... 6.3.2

Author SHA1 Message Date
Konstantin Pogorelov
2478e617bb bump 6.3.2 2021-02-18 15:31:34 +01:00
Konstantin Pogorelov
92db62dc90 run dtslint on travis with --onlyTestTsNext as a workaround for failing prom-client typing with older TS versions 2021-02-18 15:05:08 +01:00
Konstantin Pogorelov
3ffdeef8ae add linting (eslint) to travis 2021-02-18 13:04:39 +01:00
Konstantin Pogorelov
7c35f1beb6 add indentation rule for eslint 2021-02-18 13:03:25 +01:00
Konstantin Pogorelov
c44d157cfe codestyle: fix indentation 2021-02-18 13:01:26 +01:00
Konstantin Pogorelov
731fd3ec01 replace node_js v13 with v14 in travis config 2021-02-18 12:52:00 +01:00
Konstantin Pogorelov
3f587fb760 reduce minimal peer prom-client version to 12, allow any higher major version (let's be optimistic), see #76 2021-02-18 12:12:06 +01:00
Konstantin Pogorelov
3c2779d0d1 bump 6.3.1 2020-12-24 12:23:39 +01:00
Konstantin Pogorelov
a3c15b1645 support Promise response from .metrics() and .clusterMetrics(), see #71 2020-12-24 12:23:20 +01:00
Konstantin Pogorelov
f4677ce6c6 update dev. prom-client to v13, see #71 2020-12-24 12:17:02 +01:00
Konstantin Pogorelov
958453eb91 bump 6.3.0 2020-11-29 15:48:17 +01:00
Konstantin Pogorelov
0205d4cfc8 fix bypass test, minor change to docs, move bypass logic after serving the /metrics route, see MR #70 2020-11-29 15:47:28 +01:00
yacine
bffb4cf16e changed wording + added doc + unit test 2020-11-29 15:13:01 +01:00
yacine
52fdbf030f ability to exclude incoming request from metrics 2020-11-28 21:42:52 +01:00
8 changed files with 105 additions and 27 deletions

View File

@@ -17,6 +17,7 @@
"extends": "eslint:recommended",
"rules": {
"indent": [1, 2],
"array-bracket-spacing": [2, "never"],
"block-scoped-var": 2,
"brace-style": [2, "1tbs"],

View File

@@ -2,12 +2,12 @@ language: node_js
node_js:
- "10"
- "12"
- "13"
- "14"
notifications:
email: false
before_install:
- npm install prom-client
script:
- npm run lint
- npm test
- npm run dtslint
- npm run dtslint-next

View File

@@ -52,7 +52,7 @@ Which labels to include in `http_request_duration_seconds` metric:
* **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
* **metricType**: histogram/summary selection. See more details below
* **bypass**: function taking express request as an argument and determines whether the given request should be excluded in the metrics, default: **() => false**
### metricType option ###

8
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "express-prom-bundle",
"version": "6.2.0",
"version": "6.3.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -2198,9 +2198,9 @@
"dev": true
},
"prom-client": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/prom-client/-/prom-client-12.0.0.tgz",
"integrity": "sha512-JbzzHnw0VDwCvoqf8y1WDtq4wSBAbthMB1pcVI/0lzdqHGJI3KBJDXle70XK+c7Iv93Gihqo0a5LlOn+g8+DrQ==",
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/prom-client/-/prom-client-13.0.0.tgz",
"integrity": "sha512-M7ZNjIO6x+2R/vjSD13yjJPjpoZA8eEwH2Bp2Re0/PvzozD7azikv+SaBtZes4Q1ca/xHjZ4RSCuTag3YZLg1A==",
"dev": true,
"requires": {
"tdigest": "^0.1.1"

View File

@@ -1,6 +1,6 @@
{
"name": "express-prom-bundle",
"version": "6.2.0",
"version": "6.3.2",
"description": "express middleware with popular prometheus metrics in one bundle",
"main": "src/index.js",
"keywords": [
@@ -17,8 +17,10 @@
"types": "types",
"scripts": {
"test": "node_modules/jasme/run.js",
"lint": "eslint src",
"coverage": "make coverage",
"dtslint": "dtslint types"
"dtslint": "dtslint types",
"dtslint-next": "dtslint --onlyTestTsNext types"
},
"author": "Konstantin Pogorelov <or@pluseq.com>",
"license": "MIT",
@@ -36,13 +38,13 @@
"jasme": "^6.0.0",
"koa": "^2.6.2",
"koa-connect": "^2.0.1",
"prom-client": "^12.0.0",
"prom-client": "^13.0.0",
"supertest": "^3.3.0",
"supertest-koa-agent": "^0.3.0",
"typescript": "^3.4.5"
},
"peerDependencies": {
"prom-client": "^12.0.0"
"prom-client": ">=12.0.0"
},
"repository": {
"type": "git",

View File

@@ -200,6 +200,46 @@ describe('index', () => {
});
});
it('bypass requests', done => {
const app = express();
const instance = bundle({
bypass: (req)=> {
// metrics added here to attempt skipping /metrics
// this should fail though, because serving /metrics preceeds bypassing
return !!req.url.match(/test|bad.word|metrics/)
}
});
app.use(instance);
app.use('/test', (req, res) => res.send('it worked'));
app.use('/some/bad-word', (req, res) => res.send('it worked too'));
app.use('/good-word', (req, res) => res.send('this will be counted'));
const agent = supertest(app);
agent
.get('/test')
.end(() => {
agent
.get('/some/bad-word')
.end(() => {
agent
.get('/good-word')
.end(() => {
const metricHashMap = instance.metrics.http_request_duration_seconds.hashMap;
expect(metricHashMap['status_code:200']).toBeDefined();
// only /good-word should be counted
expect(metricHashMap['status_code:200'].count).toBe(1);
agent
.get('/metrics')
.end((err, res) => {
expect(res.status).toBe(200);
done();
});
});
});
});
});
it('complains about deprecated options', () => {
expect(() => bundle({prefix: 'hello'})).toThrow();
});

View File

@@ -17,20 +17,37 @@ function matchVsRegExps(element, regexps) {
}
function clusterMetrics() {
const aggregatorRegistry = new promClient.AggregatorRegistry();
const aggregatorRegistry = new promClient.AggregatorRegistry();
const metricsMiddleware = function(req, res) {
aggregatorRegistry.clusterMetrics((err, clusterMetrics) => {
if (err) {
console.error(err);
return res.sendStatus(500);
}
res.set('Content-Type', aggregatorRegistry.contentType);
res.send(clusterMetrics);
});
};
const metricsMiddleware = function(req, res) {
function sendClusterMetrics(clusterMetrics) {
res.set('Content-Type', aggregatorRegistry.contentType);
res.send(clusterMetrics);
}
return metricsMiddleware;
function sendClusterMetricsError(err) {
console.error(err);
return res.sendStatus(500);
}
// since prom-client@13 clusterMetrics() method doesn't take cb param,
// but we provide it anyway, as at this stage it's unknown which version of prom-client is used
const response = aggregatorRegistry.clusterMetrics((err, clusterMetrics) => {
if (err) {
return sendClusterMetricsError(err);
}
sendClusterMetrics(clusterMetrics);
});
// if we find out that it was a promise and our cb was useless...
if (response && response.then) {
response
.then(result => sendClusterMetrics(result))
.catch(err => sendClusterMetricsError(err));
}
};
return metricsMiddleware;
}
function main(opts) {
@@ -122,9 +139,19 @@ function main(opts) {
metrics.up.set(1);
}
const metricsMiddleware = function(req, res) {
const metricsMiddleware = function(req, res, next) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(opts.promRegistry.metrics());
const metricsResponse = opts.promRegistry.metrics();
// starting from prom-client@13 .metrics() returns a Promise
if (metricsResponse.then) {
metricsResponse
.then(output => res.end(output))
.catch(err => next(err));
} else {
// compatibility fallback for previous versions of prom-client@<=12
res.end(metricsResponse);
}
};
const metricsMatch = opts.metricsPath instanceof RegExp ? opts.metricsPath
@@ -134,7 +161,13 @@ function main(opts) {
const path = req.originalUrl || req.url; // originalUrl gets lost in koa-connect?
if (opts.autoregister && path.match(metricsMatch)) {
return metricsMiddleware(req, res);
return metricsMiddleware(req, res);
}
// bypass() is checked only after /metrics was processed
// if you wish to disable /metrics use autoregister:false instead
if (opts.bypass && opts.bypass(req)) {
return next();
}
if (opts.excludeRoutes && matchVsRegExps(path, opts.excludeRoutes)) {

2
types/index.d.ts vendored
View File

@@ -28,6 +28,8 @@ declare namespace express_prom_bundle {
includePath?: boolean;
includeUp?: boolean;
bypass?: (req: Request) => boolean;
metricType?: 'summary' | 'histogram';
metricsPath?: string;
httpDurationMetricName?: string;