mirror of
https://github.com/BreizhHardware/express-prom-bundle.git
synced 2026-01-18 16:27:28 +01:00
fixes, polishing, docs update, bump to 2.0.0
This commit is contained in:
61
README.md
61
README.md
@@ -9,8 +9,9 @@ Internally it uses **prom-client**. See: https://github.com/siimon/prom-client
|
||||
Included metrics:
|
||||
|
||||
* `up`: normally is just 1
|
||||
* `nodejs_memory_heap_total_bytes` and `nodejs_memory_heap_used_bytes`
|
||||
* `http_request_seconds`: http latency histogram labeled with `status_code`
|
||||
* `http_request_duration_seconds`: http latency histogram labeled with `status_code`, `method` and `path`
|
||||
|
||||
**Please not version 2.x is NOT compatible with 1.x**
|
||||
|
||||
## Install
|
||||
|
||||
@@ -21,9 +22,9 @@ npm install express-prom-bundle
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
const promBundle = require("express-prom-bundle"),
|
||||
metricsMiddleware = promBundle({/* options */ }),
|
||||
app = require("express")();
|
||||
const promBundle = require("express-prom-bundle");
|
||||
const metricsMiddleware = promBundle({/* options */ });
|
||||
const app = require("express")();
|
||||
|
||||
app.use(metricsMiddleware);
|
||||
app.use(/* your middleware */);
|
||||
@@ -43,23 +44,21 @@ See the example below.
|
||||
|
||||
## Options
|
||||
|
||||
* **prefix**: prefix added to every metric name
|
||||
* **whitelist**, **blacklist**: array of strings or regexp specifying which metrics to include/exclude
|
||||
* **buckets**: buckets used for `http_request_seconds` histogram
|
||||
* **includeMethod**: include HTTP method (GET, PUT, ...) as a label to `http_request_seconds`
|
||||
* **includePath**: include URL path as a label - **EXPERIMENTAL!** (see below)
|
||||
* **normalizePath**: boolean or `function(req)` - path normalization for `includePath` option
|
||||
* **excludeRoutes**: array of strings or regexp specifying which routes should be skipped for `http_request_seconds` metric. It uses `req.path` as subject when checking
|
||||
* **autoregister**: if `/metrics` endpoint should be registered. It is (Default: **true**)
|
||||
* **keepDefaultMetrics**: if default metrics provided by **prom-client** should be probed and delivered. (Default: **false**)
|
||||
* **buckets**: buckets used for `http_request_seconds` histogram
|
||||
* **includeMethod**: include HTTP method (GET, PUT, ...) as a label to `http_request_duration_seconds`
|
||||
* **includePath**: include URL path as a label (see below)
|
||||
* **normalizePath**: boolean or `function(req)` - path normalization for `includePath` option
|
||||
* **excludeRoutes**: array of strings or regexp specifying which routes should be skipped for `http_request_duration_seconds` metric. It uses `req.path` as subject when checking
|
||||
* **autoregister**: if `/metrics` endpoint should be registered. (Default: **true**)
|
||||
* **whitelist**, **blacklist**: array of strings or regexp specifying which metrics to include/exclude
|
||||
|
||||
### includePath option
|
||||
### More details on includePath option
|
||||
|
||||
The goal is to have separate latency statistics by URL path, e.g. `/my-app/user/`, `/products/by-category` etc.
|
||||
|
||||
But just taking `req.path` as a label value won't work as IDs are often part of the URL, like `/user/12352/profile`. So what we actually need is a path template. The automatically module tries to figure out what parts of the path are values or IDs, and what is an actual path. The example mentioned before would be normalized to `/user/#val/profile` and that will become the value for the label.
|
||||
Just taking `req.path` as a label value won't work as IDs are often part of the URL, like `/user/12352/profile`. So what we actually need is a path template. The module tries to figure out what parts of the path are values or IDs, and what is an actual path. The example mentioned before would be normalized to `/user/#val/profile` and that will become the value for the label.
|
||||
|
||||
You can override this magical behavior and create define your own function by providing an optional callback **normalizePath**.
|
||||
You can override this magical behavior and define your own function by providing an optional callback using **normalizePath** option.
|
||||
|
||||
For more details:
|
||||
* [url-value-parser](https://www.npmjs.com/package/url-value-parser) - magic behind automatic path normalization
|
||||
@@ -74,9 +73,9 @@ setup std. metrics but exclude `up`-metric:
|
||||
```javascript
|
||||
"use strict";
|
||||
|
||||
const express = require("express"),
|
||||
app = express(),
|
||||
promBundle = require("express-prom-bundle");
|
||||
const express = require("express");
|
||||
const app = express();
|
||||
const promBundle = require("express-prom-bundle");
|
||||
|
||||
|
||||
// calls to this route will not appear in metrics
|
||||
@@ -84,7 +83,7 @@ const express = require("express"),
|
||||
app.get("/status", (req, res) => res.send("i am healthy"));
|
||||
|
||||
app.use(promBundle({
|
||||
prefix: "demo_app:something",
|
||||
includePath: true,
|
||||
excludeRoutes: ["/foo"]
|
||||
}));
|
||||
|
||||
@@ -102,10 +101,10 @@ See an [advanced example on github](https://github.com/jochen-schweizer/express-
|
||||
## koa v1 example
|
||||
|
||||
```javascript
|
||||
const promBundle = require("express-prom-bundle"),
|
||||
koa = require("koa"),
|
||||
c2k = require("koa-connect"),
|
||||
metricsMiddleware = promBundle({/* options */ });
|
||||
const promBundle = require("express-prom-bundle");
|
||||
const koa = require("koa");
|
||||
const c2k = require("koa-connect");
|
||||
const metricsMiddleware = promBundle({/* options */ });
|
||||
|
||||
const app = koa();
|
||||
|
||||
@@ -116,6 +115,18 @@ app.listen(3000);
|
||||
|
||||
## Changelog
|
||||
|
||||
* **2.0.0**
|
||||
* the reason for the version lift were:
|
||||
* compliance to official naming recommendation: https://prometheus.io/docs/practices/naming/
|
||||
* stopping promotion of an anti-pattern - see https://groups.google.com/d/msg/prometheus-developers/XjlOnDCK9qc/ovKzV3AIBwAJ
|
||||
* dealing with **prom-client** being a singleton with a built-in registry
|
||||
* main histogram metric renamed from `http_request_seconds` to `http_request_duration_seconds`
|
||||
* options removed: **prefix**, **keepDefaultMetrics**
|
||||
* factory removed (as the only reason of it was adding the prefix)
|
||||
* upgrade prom-client to 6.3.0
|
||||
* code style changed to the one closer to express
|
||||
|
||||
|
||||
* **1.2.1**
|
||||
* upgrade prom-client to 6.1.2
|
||||
* add options: includeMethod, includePath, keepDefaultMetrics
|
||||
|
||||
@@ -4,8 +4,12 @@ const express = require('express');
|
||||
const app = express();
|
||||
const promBundle = require('express-prom-bundle');
|
||||
|
||||
// here we want to remove default metrics provided in prom-client
|
||||
// this must be done before initializing promBundle
|
||||
clearInterval(promBundle.promClient.defaultMetrics());
|
||||
promBundle.promClient.register.clear();
|
||||
|
||||
const bundle = promBundle({
|
||||
prefix: 'demo_app:something:',
|
||||
blacklist: [/up/],
|
||||
buckets: [0.1, 0.4, 0.7],
|
||||
includeMethod: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "express-prom-bundle",
|
||||
"version": "1.2.3",
|
||||
"version": "2.0.0",
|
||||
"description": "express middleware with popular prometheus metrics in one bundle",
|
||||
"main": "src/index.js",
|
||||
"keywords": [
|
||||
|
||||
@@ -9,17 +9,6 @@ const c2k = require('koa-connect');
|
||||
const supertestKoa = require('supertest-koa-agent');
|
||||
const promClient = require('prom-client');
|
||||
|
||||
// had to reinvent, because getSingleMetric() is still not in npm
|
||||
function myGetSingleMetric(name) {
|
||||
let returnMetric;
|
||||
promClient.register.getMetricsAsJSON().forEach(metric => {
|
||||
if (metric.name === name) {
|
||||
returnMetric = metric;
|
||||
}
|
||||
});
|
||||
return returnMetric;
|
||||
}
|
||||
|
||||
describe('index', () => {
|
||||
beforeEach(() => {
|
||||
promClient.register.clear();
|
||||
@@ -48,7 +37,6 @@ describe('index', () => {
|
||||
it('metrics should be attached to /metrics by default', done => {
|
||||
const app = express();
|
||||
const bundled = bundle({
|
||||
prefix: 'hello:',
|
||||
whitelist: ['up']
|
||||
});
|
||||
app.use(bundled);
|
||||
@@ -132,6 +120,7 @@ describe('index', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('filters out the excludeRoutes', done => {
|
||||
const app = express();
|
||||
const instance = bundle({
|
||||
@@ -155,19 +144,15 @@ describe('index', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('removes metrics on start with ', () => {
|
||||
new promClient.Counter('foo', 'bar');
|
||||
expect(promClient.getSingleMetric('foo')).toBeDefined();
|
||||
bundle();
|
||||
expect(promClient.getSingleMetric('foo')).not.toBeDefined();
|
||||
it('complains about deprecated options', () => {
|
||||
expect(() => bundle({prefix: 'hello'})).toThrow();
|
||||
});
|
||||
|
||||
it('tolerates includePath, includeMethod and keepDefaultMetrics', done => {
|
||||
it('tolerates includePath, includeMethod', done => {
|
||||
const app = express();
|
||||
const instance = bundle({
|
||||
includePath: true,
|
||||
includeMethod: true,
|
||||
keepDefaultMetrics: true
|
||||
includeMethod: true
|
||||
});
|
||||
app.use(instance);
|
||||
app.use('/test', (req, res) => res.send('it worked'));
|
||||
@@ -187,7 +172,6 @@ describe('index', () => {
|
||||
it('Koa: metrics returns up=1', done => {
|
||||
const app = koa();
|
||||
const bundled = bundle({
|
||||
prefix: 'hello:',
|
||||
whitelist: ['up']
|
||||
});
|
||||
app.use(c2k(bundled));
|
||||
@@ -205,7 +189,7 @@ describe('index', () => {
|
||||
.get('/metrics')
|
||||
.end((err, res) => {
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.text).toMatch(/hello:up\s1/);
|
||||
expect(res.text).toMatch(/^up\s1/m);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
19
src/index.js
19
src/index.js
@@ -49,16 +49,13 @@ function main(opts) {
|
||||
return;
|
||||
}
|
||||
|
||||
// this is a really messy hack but needed for compatibility with v1
|
||||
// will be completely removed in v2
|
||||
if (opts.keepDefaultMetrics === false) {
|
||||
const metrics = promClient.register.getMetricsAsJSON();
|
||||
clearInterval(promClient.defaultMetrics());
|
||||
metrics.forEach(metric => {
|
||||
if (!opts.prefix || metric.name.substr(0, opts.prefix.length) !== opts.prefix) {
|
||||
promClient.register.removeSingleMetric(metric.name);
|
||||
}
|
||||
});
|
||||
if (opts.prefix || opts.keepDefaultMetrics !== undefined) {
|
||||
throw new Error(
|
||||
'express-prom-bundle detected obsolete options:'
|
||||
+ 'prefix and/or keepDefaultMetrics. '
|
||||
+ 'Please refer to oficial docs. '
|
||||
+ 'Most likely you upgraded the module without necessary code changes'
|
||||
);
|
||||
}
|
||||
|
||||
const httpMtricName = opts.httpDurationMetricName || 'http_request_duration_seconds';
|
||||
@@ -68,7 +65,7 @@ function main(opts) {
|
||||
'up',
|
||||
'1 = up, 0 = not up'
|
||||
),
|
||||
'http_request_seconds': () => {
|
||||
'http_request_duration_seconds': () => {
|
||||
const labels = ['status_code'];
|
||||
if (opts.includeMethod) {
|
||||
labels.push('method');
|
||||
|
||||
Reference in New Issue
Block a user