Merge pull request #110 from ineentho/bypass-on-finish

Add new option bypassOnFinish, for when response is required in bypass callback
This commit is contained in:
Konstantin Pogorelov
2022-12-15 09:14:12 +01:00
committed by GitHub
4 changed files with 72 additions and 3 deletions

View File

@@ -52,7 +52,6 @@ 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**
* **httpDurationMetricName**: Allows you change the name of HTTP duration metric, default: **`http_request_duration_seconds`**.
### metricType option ###
@@ -90,6 +89,19 @@ Additional options for **summary**:
see [advanced example](https://github.com/jochen-schweizer/express-prom-bundle/blob/master/advanced-example.js)
* **promRegistry**: Optional `promClient.Registry` instance to attach metrics to. Defaults to global `promClient.register`.
* **metricsApp**: Allows you to attach the metrics endpoint to a different express app. You probably want to use it in combination with `autoregister: false`.
* **bypass**: An object that takes onRequest and onFinish callbacks that determines whether the given request should be excluded in the metrics. Default:
```js
{
onRequest: (req) => false,
onFinish: (req, res) => false
}
```
`onRequest` is run directly in the middleware chain, before the request is processed. `onFinish` is run after the request has been processed, and has access to the express response object in addition to the request object. Both callbacks are optional, and if one or both returns true the request is excluded.
As a shorthand, just the onRequest callback can be used instead of the object.
### More details on includePath option

View File

@@ -240,6 +240,46 @@ describe('index', () => {
});
});
it('bypass requests, checking res', done => {
const app = express();
const instance = bundle({
bypass: {
onFinish: (req, res) => res.statusCode === 404
}
});
app.use(instance);
app.use('/200', (req, res) => res.send(''));
app.use('/404', (req, res) => res.status(404).send(''));
app.use('/500', (req, res) => res.status(500).send(''));
const agent = supertest(app);
agent.get('/200')
.expect(200)
.then(() => {
return agent
.get('/404')
.expect(404);
})
.then(() => {
return agent
.get('/500')
.expect(500);
})
.then(() => {
const metricHashMap = instance.metrics.http_request_duration_seconds.hashMap;
// only /200 and /500 should be counted
expect(metricHashMap['status_code:200'].count).toBe(1);
expect(metricHashMap['status_code:404']).not.toBeDefined();
expect(metricHashMap['status_code:500'].count).toBe(1);
return agent
.get('/metrics')
.expect(200);
})
.then(done);
});
it('complains about deprecated options', () => {
expect(() => bundle({prefix: 'hello'})).toThrow();
});

View File

@@ -161,6 +161,14 @@ function main(opts) {
const metricsMatch = opts.metricsPath instanceof RegExp ? opts.metricsPath
: new RegExp('^' + (opts.metricsPath || '/metrics') + '/?$');
if (typeof opts.bypass === 'function') {
opts.bypass = {
onRequest: opts.bypass
};
} else if (!opts.bypass) {
opts.bypass = {};
}
const middleware = function (req, res, next) {
const path = req.originalUrl || req.url; // originalUrl gets lost in koa-connect?
@@ -170,7 +178,7 @@ function main(opts) {
// bypass() is checked only after /metrics was processed
// if you wish to disable /metrics use autoregister:false instead
if (opts.bypass && opts.bypass(req)) {
if (opts.bypass.onRequest && opts.bypass.onRequest(req)) {
return next();
}
@@ -182,6 +190,10 @@ function main(opts) {
const timer = metrics[httpMetricName].startTimer(labels);
onFinished(res, () => {
if (opts.bypass.onFinish && opts.bypass.onFinish(req, res)) {
return;
}
if (opts.includeStatusCode) {
labels.status_code = opts.formatStatusCode(res, opts);
}

7
types/index.d.ts vendored
View File

@@ -27,7 +27,12 @@ declare namespace express_prom_bundle {
includePath?: boolean;
includeUp?: boolean;
bypass?: (req: Request) => boolean;
bypass?:
| ((req: Request) => boolean)
| {
onRequest?: (req: Request) => boolean;
onFinish?: (req: Request, res: Response) => boolean;
};
excludeRoutes?: Array<string | RegExp>;