Skip to content
This repository has been archived by the owner on Jan 8, 2023. It is now read-only.

Commit

Permalink
feat: add metrics for request length and response length
Browse files Browse the repository at this point in the history
  • Loading branch information
matsumana committed Apr 24, 2021
1 parent 9743a84 commit 30ec2ed
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 1 deletion.
16 changes: 16 additions & 0 deletions README.md
Expand Up @@ -29,6 +29,8 @@ npm i --save express-prometheus-middleware
| collectDefaultMetrics | Whether or not to collect `prom-client` default metrics. These metrics are usefull for collecting saturation metrics, for example. | `true` |
| collectGCMetrics | Whether or not to collect garbage collection metrics via module `prometheus-gc-stats`. Dependency `prometheus-gc-stats` is marked as optional, hence if this option is set to `true` but npm/yarn could not install the dependency, no garbage collection metric will be collected. | `false` |
| requestDurationBuckets | Buckets for the request duration metrics (in seconds) histogram | Uses `prom-client` utility: `Prometheus.exponentialBuckets(0.05, 1.75, 8)` |
| requestLengthBuckets | Buckets for the request length metrics (in bytes) histogram | no buckets (The request length metrics are not collected): `[]` |
| responseLengthBuckets | Buckets for the response length metrics (in bytes) histogram | no buckets (The response length metrics are not collected) `[]` |
| extraMasks | Optional, list of regexes to be used as argument to [url-value-parser](https://www.npmjs.com/package/url-value-parser), this will cause extra route params, to be replaced with a `#val` placeholder. | no extra masks: `[]` |
| authenticate | Optional authentication callback, the function should receive as argument, the `req` object and return truthy for sucessfull authentication, or falsy, otherwise. This option supports Promise results. | `null` |
| prefix | Optional prefix for the metrics name | no prefix added |
Expand All @@ -47,6 +49,8 @@ app.use(promMid({
metricsPath: '/metrics',
collectDefaultMetrics: true,
requestDurationBuckets: [0.1, 0.5, 1, 1.5],
requestLengthBuckets: [512, 1024, 5120, 10240, 51200, 102400],
responseLengthBuckets: [512, 1024, 5120, 10240, 51200, 102400],
/**
* Uncomenting the `authenticate` callback will make the `metricsPath` route
* require authentication. This authentication callback can make a simple
Expand Down Expand Up @@ -122,6 +126,18 @@ sum(rate(http_requests_total{status="5XX", app="myapp"}[5m]))
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{app="myapp"}[5m])) by (le))
```

#### 95% of request length

```js
histogram_quantile(0.95, sum(rate(http_request_length_bytes_bucket{app="myapp"}[5m])) by (le))
```

#### 95% of response length

```js
histogram_quantile(0.95, sum(rate(http_response_length_bytes_bucket{app="myapp"}[5m])) by (le))
```

#### Average response time in seconds

```js
Expand Down
32 changes: 31 additions & 1 deletion src/index.js
Expand Up @@ -5,6 +5,8 @@ const ResponseTime = require('response-time');
const {
requestCountGenerator,
requestDurationGenerator,
requestLengthGenerator,
responseLengthGenerator,
} = require('./metrics');

const {
Expand All @@ -19,8 +21,10 @@ const defaultOptions = {
collectDefaultMetrics: true,
collectGCMetrics: false,
// buckets for response time from 0.05s to 2.5s
// these are aribtrary values since i dont know any better ¯\_(ツ)_/¯
// these are arbitrary values since i dont know any better ¯\_(ツ)_/¯
requestDurationBuckets: Prometheus.exponentialBuckets(0.05, 1.75, 8),
requestLengthBuckets: [],
responseLengthBuckets: [],
extraMasks: [],
customLabels: [],
transformLabels: null,
Expand All @@ -46,6 +50,16 @@ module.exports = (userOptions = {}) => {
options.customLabels,
options.prefix,
);
const requestLength = requestLengthGenerator(
options.customLabels,
options.requestLengthBuckets,
options.prefix,
);
const responseLength = responseLengthGenerator(
options.customLabels,
options.responseLengthBuckets,
options.prefix,
);

/**
* Corresponds to the R(equest rate), E(error rate), and D(uration of requests),
Expand All @@ -71,6 +85,22 @@ module.exports = (userOptions = {}) => {

// observe normalizing to seconds
requestDuration.observe(labels, time / 1000);

// observe request length
if (options.requestLengthBuckets.length) {
const reqLength = req.get('Content-Length');
if (reqLength) {
requestLength.observe(labels, Number(reqLength));
}
}

// observe response length
if (options.responseLengthBuckets.length) {
const resLength = res.get('Content-Length');
if (resLength) {
responseLength.observe(labels, Number(resLength));
}
}
}
});

Expand Down
30 changes: 30 additions & 0 deletions src/metrics.js
Expand Up @@ -26,7 +26,37 @@ function requestDurationGenerator(labelNames, buckets, prefix = '') {
});
}

/**
* @param {!Array} buckets - array of numbers, representing the buckets for
* @param prefix - metrics name prefix
* request length
*/
function requestLengthGenerator(labelNames, buckets, prefix = '') {
return new Prometheus.Histogram({
name: `${prefix}http_request_length_bytes`,
help: 'Content-Length of HTTP request',
labelNames,
buckets,
});
}

/**
* @param {!Array} buckets - array of numbers, representing the buckets for
* @param prefix - metrics name prefix
* response length
*/
function responseLengthGenerator(labelNames, buckets, prefix = '') {
return new Prometheus.Histogram({
name: `${prefix}http_response_length_bytes`,
help: 'Content-Length of HTTP response',
labelNames,
buckets,
});
}

module.exports = {
requestCountGenerator,
requestDurationGenerator,
requestLengthGenerator,
responseLengthGenerator,
};

0 comments on commit 30ec2ed

Please sign in to comment.