feat: respect pruneAgedBuckets, update README

This commit is contained in:
Timm Stelzer
2024-01-06 11:31:26 +01:00
committed by Konstantin Pogorelov
parent edfb9992ed
commit fd5ff1cfe0
4 changed files with 60 additions and 13 deletions

View File

@@ -69,6 +69,7 @@ Additional options for **summary**:
* **percentiles**: percentiles used for `http_request_duration_seconds` summary * **percentiles**: percentiles used for `http_request_duration_seconds` summary
* **ageBuckets**: ageBuckets configures how many buckets we have in our sliding window for the summary * **ageBuckets**: ageBuckets configures how many buckets we have in our sliding window for the summary
* **maxAgeSeconds**: the maxAgeSeconds will tell how old a bucket can be before it is reset * **maxAgeSeconds**: the maxAgeSeconds will tell how old a bucket can be before it is reset
* **pruneAgedBuckets**: When enabled, timed out buckets will be removed entirely. By default, buckets are reset to 0.
### Transformation callbacks ### ### Transformation callbacks ###

View File

@@ -20,6 +20,10 @@ function extractBucket (instance, key) {
} }
} }
function getMetricCount (s) {
return s.replace(/^#.*$\n|^$\n/gm, '').trim().split('\n').length;
}
describe('index', () => { describe('index', () => {
beforeEach(() => { beforeEach(() => {
promClient.register.clear(); promClient.register.clear();
@@ -342,7 +346,7 @@ describe('index', () => {
describe('usage of normalizePath()', () => { describe('usage of normalizePath()', () => {
it('normalizePath can be replaced gloablly', done => { it('normalizePath can be replaced globally', done => {
const app = express(); const app = express();
const original = bundle.normalizePath; const original = bundle.normalizePath;
bundle.normalizePath = () => 'dummy'; bundle.normalizePath = () => 'dummy';
@@ -366,6 +370,40 @@ describe('index', () => {
}); });
}); });
it('respects pruneAgedBuckets', done => {
const app = express();
const metricsApp = express();
const bundled = bundle({
metricsApp,
metricType: 'summary',
includePath: true,
maxAgeSeconds: 1,
percentiles: [0.5],
ageBuckets: 1,
pruneAgedBuckets: true,
});
app.use(bundled);
const agent = supertest(app);
const metricsAgent = supertest(metricsApp);
agent.get('/foo')
.then(() => metricsAgent.get('/metrics'))
.then(response => {
expect(response.status).toBe(200);
// up + bucket, sum, count
expect(getMetricCount(response.text)).toBe(4);
})
.then(() => new Promise(r => setTimeout(r, 1010)))
.then(() => metricsAgent.get('/metrics'))
.then(response => {
expect(response.status).toBe(200);
// only up
expect(getMetricCount(response.text)).toBe(1);
})
.finally(done);
});
it('normalizePath function can be overridden', done => { it('normalizePath function can be overridden', done => {
const app = express(); const app = express();
const instance = bundle({ const instance = bundle({

View File

@@ -112,7 +112,8 @@ function main(opts) {
percentiles: opts.percentiles || [0.5, 0.75, 0.95, 0.98, 0.99, 0.999], percentiles: opts.percentiles || [0.5, 0.75, 0.95, 0.98, 0.99, 0.999],
maxAgeSeconds: opts.maxAgeSeconds, maxAgeSeconds: opts.maxAgeSeconds,
ageBuckets: opts.ageBuckets, ageBuckets: opts.ageBuckets,
registers: [opts.promRegistry] registers: [opts.promRegistry],
pruneAgedBuckets: opts.pruneAgedBuckets
}); });
} else if (opts.metricType === 'histogram' || !opts.metricType) { } else if (opts.metricType === 'histogram' || !opts.metricType) {
return new promClient.Histogram({ return new promClient.Histogram({

29
types/index.d.ts vendored
View File

@@ -17,7 +17,7 @@ declare namespace express_prom_bundle {
type NormalizeStatusCodeFn = (res: Response) => number | string; type NormalizeStatusCodeFn = (res: Response) => number | string;
type TransformLabelsFn = (labels: Labels, req: Request, res: Response) => void; type TransformLabelsFn = (labels: Labels, req: Request, res: Response) => void;
interface Opts { interface BaseOptions {
autoregister?: boolean; autoregister?: boolean;
customLabels?: { [key: string]: any }; customLabels?: { [key: string]: any };
@@ -36,16 +36,6 @@ declare namespace express_prom_bundle {
excludeRoutes?: Array<string | RegExp>; excludeRoutes?: Array<string | RegExp>;
metricType?: 'summary' | 'histogram';
// https://github.com/siimon/prom-client#histogram
buckets?: number[];
// https://github.com/siimon/prom-client#summary
percentiles?: number[];
maxAgeSeconds?: number;
ageBuckets?: number;
metricsPath?: string; metricsPath?: string;
httpDurationMetricName?: string; httpDurationMetricName?: string;
promClient?: { collectDefaultMetrics?: DefaultMetricsCollectorConfiguration<RegistryContentType> }; promClient?: { collectDefaultMetrics?: DefaultMetricsCollectorConfiguration<RegistryContentType> };
@@ -65,6 +55,23 @@ declare namespace express_prom_bundle {
}; };
} }
/** @see https://github.com/siimon/prom-client#summary */
type SummaryOptions = BaseOptions & {
metricType?: 'summary';
percentiles?: number[];
maxAgeSeconds?: number;
ageBuckets?: number;
pruneAgedBuckets?: boolean;
}
/** @see https://github.com/siimon/prom-client#histogram */
type HistogramOptions = BaseOptions & {
metricType?: 'histogram';
buckets?: number[];
}
type Opts = SummaryOptions | HistogramOptions;
interface Middleware extends RequestHandler { interface Middleware extends RequestHandler {
metricsMiddleware: RequestHandler; metricsMiddleware: RequestHandler;
} }