Skip to content

Commit

Permalink
feat: support regular expressions in routeBlacklist values (#98)
Browse files Browse the repository at this point in the history
* feat: support route blacklist values using regexp

* test: support route blacklist values using regexp

* docs(readme): update routeBlacklist type

* docs: regenerate with api-extractor
  • Loading branch information
dmuharemagic authored Dec 19, 2023
1 parent 7d68680 commit fabf6d7
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 10 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ See for details [docs](docs/api/fastify-metrics.imetricspluginoptions.md)
| [overrides?](./docs/fastify-metrics.iroutemetricsconfig.overrides.md) | [IRouteMetricsOverrides](./docs/fastify-metrics.iroutemetricsoverrides.md) | |
| [registeredRoutesOnly?](./docs/fastify-metrics.iroutemetricsconfig.registeredroutesonly.md) | boolean | `true` |
| [customLabels?](./fastify-metrics.iroutemetricsconfig.customlabels.md) | Record<string, string \| ((request: FastifyRequest, reply: FastifyReply) => string)> | `undefined` |
| [routeBlacklist?](./docs/fastify-metrics.iroutemetricsconfig.routeblacklist.md) | readonly string\[\] | `[]` |
| [routeBlacklist?](./docs/fastify-metrics.iroutemetricsconfig.routeblacklist.md) | readonly (string \| RegExp)\[\] | `[]` |

#### Route metrics enabled

Expand Down
2 changes: 1 addition & 1 deletion docs/api/fastify-metrics.iroutemetricsconfig.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ export interface IRouteMetricsConfig
| [methodBlacklist?](./fastify-metrics.iroutemetricsconfig.methodblacklist.md) | | readonly HTTPMethods\[\] | <i>(Optional)</i> A list of HTTP methods that will be excluded from metrics collection |
| [overrides?](./fastify-metrics.iroutemetricsconfig.overrides.md) | | [IRouteMetricsOverrides](./fastify-metrics.iroutemetricsoverrides.md) | <i>(Optional)</i> Metric configuration overrides |
| [registeredRoutesOnly?](./fastify-metrics.iroutemetricsconfig.registeredroutesonly.md) | | boolean | <i>(Optional)</i> Collect metrics only for registered routes. If <code>false</code>, then metrics for unknown routes <code>/unknown-unregistered-route</code> will be collected as well. |
| [routeBlacklist?](./fastify-metrics.iroutemetricsconfig.routeblacklist.md) | | readonly string\[\] | <i>(Optional)</i> A list of routes that will be excluded from metrics collection. |
| [routeBlacklist?](./fastify-metrics.iroutemetricsconfig.routeblacklist.md) | | readonly (string \| RegExp)\[\] | <i>(Optional)</i> A list of routes that will be excluded from metrics collection. |
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ A list of routes that will be excluded from metrics collection.
<b>Signature:</b>

```typescript
routeBlacklist?: readonly string[];
routeBlacklist?: readonly (string | RegExp)[];
```
14 changes: 11 additions & 3 deletions etc/fastify-metrics.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
```ts
import client from 'prom-client';
import { DefaultMetricsCollectorConfiguration } from 'prom-client';
import { FastifyBaseLogger } from 'fastify';
import { FastifyPluginAsync } from 'fastify';
import { FastifyReply } from 'fastify';
import { FastifyRequest } from 'fastify';
Expand All @@ -19,7 +20,8 @@ import { SummaryConfiguration } from 'prom-client';
const _default: FastifyPluginAsync<
Partial<IMetricsPluginOptions>,
RawServerDefault,
FastifyTypeProviderDefault
FastifyTypeProviderDefault,
FastifyBaseLogger
>;
export default _default;

Expand Down Expand Up @@ -72,13 +74,19 @@ export interface IRouteMetricsConfig {
string,
string | ((request: FastifyRequest, reply: FastifyReply) => string)
>;
enabled?: boolean;
// (undocumented)
enabled?:
| boolean
| {
histogram?: boolean;
summary?: boolean;
};
groupStatusCodes?: boolean;
invalidRouteGroup?: string;
methodBlacklist?: readonly HTTPMethods[];
overrides?: IRouteMetricsOverrides;
registeredRoutesOnly?: boolean;
routeBlacklist?: readonly string[];
routeBlacklist?: readonly (string | RegExp)[];
}

// @public
Expand Down
83 changes: 83 additions & 0 deletions src/__tests__/route-metrics.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,89 @@ describe('route metrics', () => {
});
});

describe(`{ routeBlacklist = [/^\\/api\\/documentation(\\/|$)/] }`, () => {
let app = fastify();

afterEach(async () => {
await app.close();
});

beforeEach(async () => {
app = fastify();

await app.register(fastifyPlugin, {
endpoint: '/metrics',
routeMetrics: {
enabled: true,
routeBlacklist: [/^\/api\/documentation(\/|$)/],
},
});
app.get('/api/documentation', async () => {
return 'Base documentation';
});
app.get('/api/documentation/json', async () => {
return 'JSON documentation';
});
app.get('/api/documentation/yaml', async () => {
return 'YAML documentation';
});
app.get('/api/other', async () => {
return 'Other API endpoint';
});
await app.ready();
});

test('metrics for regex matched routes in blacklist not exposed', async () => {
await expect(
app.inject({
method: 'GET',
url: '/api/documentation',
})
).resolves.toBeDefined();

await expect(
app.inject({
method: 'GET',
url: '/api/documentation/json',
})
).resolves.toBeDefined();

await expect(
app.inject({
method: 'GET',
url: '/api/documentation/yaml',
})
).resolves.toBeDefined();

await expect(
app.inject({
method: 'GET',
url: '/api/other',
})
).resolves.toBeDefined();

const metrics = await app.inject({
method: 'GET',
url: '/metrics',
});

expect(typeof metrics.payload).toBe('string');

const lines = metrics.payload.split('\n');

expect(lines).toEqual(
expect.not.arrayContaining([
expect.stringContaining('route="/api/documentation"'),
expect.stringContaining('route="/api/documentation/json"'),
expect.stringContaining('route="/api/documentation/yaml"'),
])
);
expect(lines).toEqual(
expect.arrayContaining([expect.stringContaining('route="/api/other"')])
);
});
});

describe(`{ methodBlacklist = ['GET'] }`, () => {
let app = fastify();

Expand Down
10 changes: 7 additions & 3 deletions src/fastify-metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,13 @@ export class FastifyMetrics implements IFastifyMetrics {
// routeOptions.routePath; // the URL of the route without the prefix
// routeOptions.prefix;

if (
this.options.routeMetrics.routeBlacklist?.includes(routeOptions.url)
) {
const isRouteBlacklisted = this.options.routeMetrics.routeBlacklist?.some(
(pattern) =>
typeof pattern === 'string'
? pattern === routeOptions.url
: pattern.test(routeOptions.url)
);
if (isRouteBlacklisted) {
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export interface IRouteMetricsConfig {
*
* @defaultValue `undefined`
*/
routeBlacklist?: readonly string[];
routeBlacklist?: readonly (string | RegExp)[];

/**
* A list of HTTP methods that will be excluded from metrics collection
Expand Down

0 comments on commit fabf6d7

Please sign in to comment.