Giter Site home page Giter Site logo

skellla / fastify-metrics Goto Github PK

View Code? Open in Web Editor NEW
85.0 4.0 32.0 1.41 MB

Prometheus metrics exporter for Fastify

Home Page: https://savelife.in.ua/en/donate-en/

License: MIT License

JavaScript 6.87% TypeScript 93.13%
fastify fastify-plugin metrics prometheus

fastify-metrics's Introduction

fastify-metrics

fastify-metrics logo

NPM Version Downloads Count Vunerabilities Count Build Status License Codecov

Prometheus metrics exporter for Fastify.

This plugin uses prom-client under the hood.

This plugin also adds two http metrics for your routes:

  • Requests duration histogram
  • Requests duration summary

ToC

Fastify support

  • v3.x.x - supports fastify-1.x
  • v4.x.x - supports fastify-2.x prom-client-11.x
  • v5.x.x - supports fastify-2.x prom-client-12.x
  • v6.x.x - supports fastify-3.x
  • v9.x.x - supports fastify-4.x prom-client-14.x

Notable changes

v10.x.x

  • Replace route context.config with routeConfig due to deprecation in fastify v4 and removal in fastify v5. If you had disableMetrics option in you route config, update fastify to latest version.
  • Prefer request.routeOptions.method over deprecated request.routerMethod.

v9.x.x

  • Fastify v4 support.
  • Complete config rewrite, default behaviour changed.
  • Support disabling metrics in route config.
  • Now collects metrics only for registered routes by default.
  • Unknown routes metrics collection disabled by default.
  • Removed metrics from request. Now it uses WeakMap and not exposed.
  • Add balcklisting possibility for request methods.
  • Registry overrides moved to metric configuration.
  • Support overriding all Summary and Histogram options for default route metrics.

v6.x.x

  • Fastify v3 support.
  • Drop node.js 8 support.
  • enableDefaultMetrics - now enables only default prom-client metrics. Set to true by default.
  • enableRouteMetrics - additional flag that enables route metrics. Set to true by default.

Installation

npm i fastify-metrics --save
pnpm i fastify-metrics --save

Back to top

Features and requirements

  • Collects default server metrics (see prom-client);
  • Collects route response timings
  • Adds metrics to fastify instance for your custom metrics.

  • Requires fastify >=4.0.0.
  • Node.js >=18.0.0.

Back to top

Usage

Add it to your project like regular fastify plugin. Use register method and pass options to it.

const fastify = require('fastify');
const app = fastify();

const metricsPlugin = require('fastify-metrics');
await app.register(metricsPlugin, { endpoint: '/metrics' });

It also exports client to fastify instance fastify.metrics.client which you may use it in your routes.

You may create your metrics when app starts and store it in fastify.metrics object and reuse them in multiple routes.

Registry clear

After calling registry.clear() all metrics are removed from registry. In order to add them again to the registry, call fastify.mterics.initMetricsInRegistry.

Back to top

Plugin options

See for details docs

Property Type Default Value
defaultMetrics? IDefaultMetricsConfig { enabled: true }
endpoint? string | null | Fastify.RouteOptions '/metrics'
name? string 'metrics'
routeMetrics? IRouteMetricsConfig { enabled: true }
promClient? prom-client instance | null null

Route metrics

Property Type Default Value
enabled? boolean | { histogram: boolean, summary: boolean } true
enableSummaries? boolean true
groupStatusCodes? boolean false
invalidRouteGroup? string '__unknown__'
methodBlacklist? readonly string[] ['HEAD','OPTIONS','TRACE','CONNECT',]
overrides? IRouteMetricsOverrides
registeredRoutesOnly? boolean true
customLabels? Record<string, string | ((request: FastifyRequest, reply: FastifyReply) => string)> undefined
routeBlacklist? readonly (string | RegExp)[] []

Route metrics enabled

The enabled configuration option can be either a boolean which enables/disables generation of both histograms and summaries, or it can be set to an object that allows you to pick individually whether you want histograms or summaries to be generated, for example:

{
  ...
  routeMetrics: {
    enabled: {
      histogram: true,
      summary: false
    }
  }
}

would result in the library only generating histograms.

Route metrics overrides

You may override default metrics settings. You may provide overrides for two metrics tracking http request durations: histogram and summary.

const fastify = require('fastify');
const app = fastify();
const metricsPlugin = require('fastify-metrics');

await app.register(metricsPlugin, {
  endpoint: '/metrics',
  routeMetrics: {
    overrides: {
      histogram: {
        name: 'my_custom_http_request_duration_seconds',
        buckets: [0.1, 0.5, 1, 3, 5],
      },
      summary: {
        help: 'custom request duration in seconds summary help',
        labelNames: ['status_code', 'method', 'route'],
        percentiles: [0.5, 0.75, 0.9, 0.95, 0.99],
      },
    },
  },
});
Labels
Property Type Default value
getRouteLabel? (request: FastifyRequest) => string undefined
method? string 'method'
route? string 'route'
status? string 'status_code'
Request durations summary
Property Type Default value
name? string 'http_request_summary_seconds'
help? string 'request duration in seconds summary'
percentiles? number[] [0.5, 0.9, 0.95, 0.99]
Request durations histogram
Property Type Default value
name? string 'http_request_duration_seconds'
help? string 'request duration in seconds'
buckets? number[] [0.05, 0.1, 0.5, 1, 3, 5, 10]

Back to top

HTTP routes metrics in Prometheus

The following table shows what metrics will be available in Prometheus (subject to the enabled configuration option). Note suffixes like _bucket, _sum, _count are added automatically.

metric labels description
http_request_duration_seconds_count method, route, status_code Requests total count
http_request_duration_seconds_bucket method, route, status_code Requests durations by bucket
http_request_summary_seconds method, route, status_code Requests duration percentiles
http_request_summary_seconds_count method, route, status_code Requests total count

Back to top

API Docs

See docs.

Back to top

Changelog

See changelog.

Back to top

See also

Back to top

License

Licensed under MIT.

Back to top

fastify-metrics's People

Contributors

dependabot[bot] avatar dmuharemagic avatar gausnes avatar gugu avatar hanzhangyu avatar hiddenboox avatar iamelevich avatar joice avatar juleswritescode avatar kibertoad avatar leorossi avatar lgtm-migrator avatar mcollina avatar melzmr avatar neriuzz avatar p-kuen avatar richardnias avatar rozzilla avatar semantic-release-bot avatar sg-gs avatar skellla avatar steffen8608 avatar turneand avatar wiktor-obrebski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

fastify-metrics's Issues

auth support

It would be great to support authentication for scraping requests.

api proposal:

  app.register(fastifyMetrics, {
    endpoint: '/metrics',
    authFn: (req) => { return req.body.apiKey === 'myPassphrase' }
  })

warning message

(node:3218427) [FSTDEP012] FastifyDeprecation: Request#context property access is deprecated. Please use "Request#routeConfig" or "Request#routeSchema" instead for accessing Route settings. The "Request#context" will be removed in fastify@5.

my fastify version 4.7.0

Use of deprecated routerMethod in fastify

(node:54086) [FSTDEP018] FastifyDeprecation: You are accessing the deprecated "request.routerMethod" property. Use "request.routeOptions.method" instead. Property "req.routerMethod" will be removed in fastify@5.

 "fastify": "4.23.2",
 "fastify-metrics": "10.3.2",

Custom metrics - LabelNames property breaks registration of metric

Hi,

testing out your great repo. There is a bug in regards to registering custom metrics via the included prom-client:

Once the LabelNames property is being used (to declare labels for a custom metric), the metric registration fails. This seems to work just fine in the prom-client package, here's an example regarding LabelNames taken from their docs adjusted for fastify-metrics

// (1) this works
const res_gauge_1 = new fastify.metrics.client.Gauge({
    name: 'test_gauge_1',
    help: 'my test gauge 1',
});
// (2) this does NOT work
const res_gauge_2 = new fastify.metrics.client.Gauge({
    name: 'test_gauge_2',
    help: 'my test gauge 2',
    labelNames: ['test'],     // <--- breaks registration
});

See link above that this should work.

stack:
fastify-metrics: 7.4.0 (latest)
Node: 16.5.0
OS; Win 10 x64

Thanks.

Plugin type mismatch when using fastify-metrics in an ESM project

Since some 3rd party librairies I use in my project are now only packaged for ESM, I decided to migrate my TypeScript project from CommonJS to ESM ("module": "nodenext" and "moduleResolution": "nodenext" in tsconfig.json)

I have an issue with fastify-metrics: when registering, the type of metricsPlugin is no longer considered as matching the expected type :

import metricsPlugin from 'fastify-metrics'
...
fastify.register(metricsPlugin, { endpoint: '/metrics' })

=>

src/app.ts:52:18 - error TS2769: No overload matches this call.
  Overload 1 of 3, '(plugin: FastifyPluginCallback<{ endpoint: string; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
    Argument of type 'typeof import("/workspace/coucou/server/node_modules/fastify-metrics/dist/index")' is not assignable to parameter of type 'FastifyPluginCallback<{ endpoint: string; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>'.
      Type 'typeof import("/workspace/coucou/server/node_modules/fastify-metrics/dist/index")' provides no match for the signature '(instance: FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProvider>, opts: { ...; }, done: (err?: Error | undefined) => void): void'.
  Overload 2 of 3, '(plugin: FastifyPluginAsync<{ endpoint: string; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
    Argument of type 'typeof import("/workspace/coucou/server/node_modules/fastify-metrics/dist/index")' is not assignable to parameter of type 'FastifyPluginAsync<{ endpoint: string; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger>'.
      Type 'typeof import("/workspace/coucou/server/node_modules/fastify-metrics/dist/index")' provides no match for the signature '(instance: FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProvider>, opts: { ...; }): Promise<...>'.
  Overload 3 of 3, '(plugin: FastifyPluginCallback<{ endpoint: string; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger> | FastifyPluginAsync<...> | Promise<...> | Promise<...>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
    Argument of type 'typeof import("/workspace/coucou/server/node_modules/fastify-metrics/dist/index")' is not assignable to parameter of type 'FastifyPluginCallback<{ endpoint: string; }, RawServerDefault, FastifyTypeProvider, FastifyBaseLogger> | FastifyPluginAsync<...> | Promise<...> | Promise<...>'.

52 fastify.register(metricsPlugin, { endpoint: '/metrics' })

Am I doing something wrong? It worked when my project was CommonJS.

As a workaround I did this:

fastify.register(metricsPlugin as unknown as FastifyPluginAsync<Partial<IMetricsPluginOptions>>, {
  endpoint: '/metrics'
})

[bug] new routeConfig types break route config for other plugins

Hey hi!

After updating to v7.4.0, I ran into some issues with my other config options. It appears that the update doesn't let any other plugins or custom config options be entered other than the ones for this plugin.

CleanShot 2022-09-30 at 20 16 54@2x

I haven't fully figured out the issue, but it looks like something with the overwriting of the context config? The @fastify/rate-limit plugin I'm using doesn't implement any types, and config should still work for any config, even ones without types defined.

Package version things:
@fastify/rate-limit: 7.4.0
fastify: 4.7.0
fastify-metrics: 9.2.2

Thank you!

Endpoint is not registered when enableRouteMetrics is false

Reading the documentation, I understood that if pass enableRouteMetrics: false at the plugin configuration, the plugin would only stop exporting route metrics, but would still export a route with default metrics if endpoint is configured. However, this is not happening. When I use the following configuration, accessing /metrics results in 404:

app.register(metricsPlugin, {
	enableRouteMetrics: false,
	endpoint: '/metrics',
});

Passing `enableDefaultMetrics: false` disables the whole plugin

if (enableDefaultMetrics) wrap the whole plugin, including the hooks

if (enableDefaultMetrics) {
const collectMetricsForUrl = (url: string) => {
const queryIndex = url.indexOf('?');
url = queryIndex === -1 ? url : url.substring(0, queryIndex);
if (!blacklist) {
return true;
}
if (Array.isArray(blacklist)) {
return blacklist.indexOf(url) === -1;
}
if (typeof blacklist === 'string') {
return blacklist !== url;
}
if (typeof blacklist.test === 'function') {
return !blacklist.test(url);
}
return false;
};
const defaultOpts: client.DefaultMetricsCollectorConfiguration = {};
const opts: MetricConfig = {
histogram: {
name: 'http_request_duration_seconds',
help: 'request duration in seconds',
labelNames: ['status_code', 'method', 'route'],
buckets: [0.05, 0.1, 0.5, 1, 3, 5, 10],
},
summary: {
name: 'http_request_summary_seconds',
help: 'request duration in seconds summary',
labelNames: ['status_code', 'method', 'route'],
percentiles: [0.5, 0.9, 0.95, 0.99],
},
};
if (register) {
plugin.clearRegister = () => {
register.clear();
};
defaultOpts.register = register;
opts.histogram.registers = [register];
opts.summary.registers = [register];
}
if (prefix) {
defaultOpts.prefix = prefix;
opts.histogram.name = `${prefix}${opts.histogram.name}`;
opts.summary.name = `${prefix}${opts.summary.name}`;
}
const extendedOpts = merge<MetricConfig>(opts, metrics);
client.collectDefaultMetrics(defaultOpts);
const routeHist = new client.Histogram(extendedOpts.histogram);
const routeSum = new client.Summary(extendedOpts.summary);
if (endpoint) {
fastify.route({
url: endpoint,
method: 'GET',
schema: {
// hide route from swagger plugins
hide: true,
},
handler: (_, reply) => {
const data = register
? register.metrics()
: client.register.metrics();
reply.type('text/plain').send(data);
},
});
}
fastify.addHook('onRequest', (request, _, next) => {
if (request.raw.url && collectMetricsForUrl(request.raw.url)) {
request.metrics = {
hist: routeHist.startTimer(),
sum: routeSum.startTimer(),
};
}
next();
});
fastify.addHook('onResponse', function (request, reply, next) {
if (request.metrics) {
const context: FastifyContext<MetricsContextConfig> = reply.context as FastifyContext<
MetricsContextConfig
>;
let routeId = context.config.url || request.raw.url;
if (context.config.statsId) {
routeId = context.config.statsId;
}
const method = request.raw.method;
const statusCode = groupStatusCodes
? `${Math.floor(reply.raw.statusCode / 100)}xx`
: reply.raw.statusCode;
request.metrics.sum({
method: method || 'UNKNOWN',
route: routeId,
status_code: statusCode,
});
request.metrics.hist({
method: method || 'UNKNOWN',
route: routeId,
status_code: statusCode,
});
}
next();
});
}

Default labels missing on custom metrics

Default metrics like system CPU have the default label (foo=bar), however, custom metrics like accountDeleted do not have the default label, even though it has been registered. As far as I can recall, this used to work with 8.x.

metrics.ts

import client from 'prom-client';

client.register.setDefaultLabels({foo: 'bar'});

const accountDeleted = new client.Counter({
  name: 'account_deleted',
  help: 'Adds one whenever an account is deleted'
});

export const metrics = {
  accountDeleted,
  defaultLabels,
  register: client.register,
};

app.ts

  await app.register(fastifyMetrics, {
    endpoint: '/metrics',
    defaultMetrics: {
      enabled: true,
      labels: {foo: 'bar'},
      register: metrics.register
    }
  });

Result in metrics:

account_deleted 1
process_cpu_user_seconds_total{foo="bar"} 3.608122

Expected:

account_deleted{foo="bar"} 1
process_cpu_user_seconds_total{foo="bar"} 3.608122

Add new http default metrics

@SkeLLLa What do you think about adding new HTTP-related default metrics like total req count, req per sec, req per min, failure req count?

You already have a lot of what it takes to support these metrics: ignoring http methods/routes, subscriptions on fastify hooks, gathering status codes, etc.

HEAD requests pollute metrics with routes including query parameters

Reproduction

After this line: https://github.com/SkeLLLa/fastify-metrics/blob/master/src/index.ts#L164 in the onResponse hook, add:

console.log('context.config.url: ' , context.config.url);
console.log('context.config.statsId: ' , context.config.statsId);
console.log('request.raw.url: ' , request.raw.url);
console.log('routeId: ' , routeId);
$ curl --get http://localhost/foo/\?x\=1
$ curl --head http://localhost/foo/\?x\=1

Expected

Last line ('routeId: ') should be /foo/ in both cases

Actual

GET

context.config.url:  /foo/
context.config.statsId:  undefined
request.raw.url:  /foo/?x=1
routeId:  /foo/

HEAD

context.config.url:  undefined
context.config.statsId:  undefined
request.raw.url:  /foo/?x=1
routeId:  /foo/?x=1

Why this is a problem

This splits up the metrics for the /foo/ route and creates thousands of differently-labeled metrics:

http_request_duration_seconds_bucket{le="0.05",method="HEAD",route="/foo/?x=1",status_code="200"} 1
http_request_duration_seconds_bucket{le="0.1",method="HEAD",route="/foo/?x=1",status_code="200"} 1
http_request_duration_seconds_bucket{le="0.5",method="HEAD",route="/foo/?x=1",status_code="200"} 1
http_request_duration_seconds_bucket{le="1",method="HEAD",route="/foo/?x=1",status_code="200"} 1
http_request_duration_seconds_bucket{le="3",method="HEAD",route="/foo/?x=1",status_code="200"} 1
http_request_duration_seconds_bucket{le="5",method="HEAD",route="/foo/?x=1",status_code="200"} 1
http_request_duration_seconds_bucket{le="10",method="HEAD",route="/foo/?x=1",status_code="200"} 1
http_request_duration_seconds_bucket{le="+Inf",method="HEAD",route="/foo/?x=1",status_code="200"} 1
http_request_duration_seconds_bucket{le="0.05",method="HEAD",route="/foo/?x=2",status_code="200"} 1
http_request_duration_seconds_bucket{le="0.1",method="HEAD",route="/foo/?x=2",status_code="200"} 1
http_request_duration_seconds_bucket{le="0.5",method="HEAD",route="/foo/?x=2",status_code="200"} 1
http_request_duration_seconds_bucket{le="1",method="HEAD",route="/foo/?x=2",status_code="200"} 1
http_request_duration_seconds_bucket{le="3",method="HEAD",route="/foo/?x=2",status_code="200"} 1
http_request_duration_seconds_bucket{le="5",method="HEAD",route="/foo/?x=2",status_code="200"} 1
http_request_duration_seconds_bucket{le="10",method="HEAD",route="/foo/?x=2",status_code="200"} 1
http_request_duration_seconds_bucket{le="+Inf",method="HEAD",route="/foo/?x=2",status_code="200"} 1
http_request_duration_seconds_bucket{le="0.05",method="HEAD",route="/foo/?x=3",status_code="200"} 1
http_request_duration_seconds_bucket{le="0.1",method="HEAD",route="/foo/?x=3",status_code="200"} 1
http_request_duration_seconds_bucket{le="0.5",method="HEAD",route="/foo/?x=3",status_code="200"} 1
http_request_duration_seconds_bucket{le="1",method="HEAD",route="/foo/?x=3",status_code="200"} 1
http_request_duration_seconds_bucket{le="3",method="HEAD",route="/foo/?x=3",status_code="200"} 1
http_request_duration_seconds_bucket{le="5",method="HEAD",route="/foo/?x=3",status_code="200"} 1
http_request_duration_seconds_bucket{le="10",method="HEAD",route="/foo/?x=3",status_code="200"} 1
http_request_duration_seconds_bucket{le="+Inf",method="HEAD",route="/foo/?x=3",status_code="200"} 1

etc. etc.

Use of deprecated routeConfig in fastify

(node:463) [FSTDEP016] FastifyDeprecation: You are accessing the deprecated "request.routeConfig" property. Use "request.routeOptions.config" instead. Property "req.routeConfig" will be removed in `fastify@5`.
FastifyDeprecation: You are accessing the deprecated "request.routeConfig" property. Use "request.routeOptions.config" instead. Property "req.routeConfig" will be removed in `fastify@5`.
    at Object.emit (/srv/shorturl_redirector/node_modules/process-warning/index.js:55:13)
    at _Request.get (/srv/shorturl_redirector/node_modules/fastify/lib/request.js:217:15)
    at FastifyMetrics.defaultGetRouteLabel (/srv/shorturl_redirector/node_modules/fastify-metrics/src/fastify-metrics.ts:88:15)
    at Object.<anonymous> (/srv/shorturl_redirector/node_modules/fastify-metrics/src/fastify-metrics.ts:337:28)
    at onResponseHookIterator (/srv/shorturl_redirector/node_modules/fastify/lib/hooks.js:270:10)
    at next (/srv/shorturl_redirector/node_modules/fastify/lib/hooks.js:243:18)
    at hookRunner (/srv/shorturl_redirector/node_modules/fastify/lib/hooks.js:265:5)
    at Response.onResFinished (/srv/shorturl_redirector/node_modules/fastify/lib/reply.js:775:7)
    at Response.emit (node:events:523:35)
    at Response.emit (node:domain:489:12)

opentelemetry

Any consideration to supporting opentelemetry's metrics sdk? This would make this library agnostic to the specific metrics backend (prometheus or otherwise).

Thanks for the great work!

Support for fastify 4

With the second release candidate of fastify 4 being out, are there any plans to support Fastify v4?

[Security]: Vulnerable to `Challenge Collapsar`

The current plugin has enableRouteMetrics turned on by default

fastify-metrics will record all http requests and put them in memory
when the server suffers a Challenge Collapsar Attack , the data in memory will grow and never be cleared
because grafana gets statistics every once in a while, the entire nodejs process is blocked
eventually, the server becomes unavailable

图片

图片

图片

图片


You can use https://github.com/projectdiscovery/nuclei to perform simulation tests (./nuclei -u domain)
This tool will make 150 requests per second, with 10 concurrent

Can't register plugin multiple times

Hello, currently it's not possible to register the plugin multiple times. An error is thrown by the prom client that the metric was already added. This happening because the plugin uses the global prom registry.

This feature is very valuable for testing.

Broken ESM export in v9

Looks like you are double-exporting a default when importing in node esm module mode.

var a = await import('fastify-metrics')
undefined
> a
[Module: null prototype] {
  __esModule: true,
  default: {
    default: <ref *1> [AsyncFunction (anonymous)] {
      default: [Circular *1],
      [Symbol(skip-override)]: true,
      [Symbol(fastify.display-name)]: 'index-auto-0',
      [Symbol(plugin-meta)]: [Object]
    }
  }
}
> 

Unable to prefix names of default metrics in v9 as `prefix` option from v8.0.0 is not a thing in v9

Hello,

I upgraded fastify-metrics from 8.0.0 to 9.2.1. Changed plugin registration code to use new configuration options. Metrics are being collected and exposed under the route I want. However, I didn't found any way to add custom prefix to default metric names. prefix option available in 8.0.0 no longer works.

I am wondering if this is an expected behavior? And if so, what is the rationale behind this breaking change or maybe there are some workarounds?

With custom metrics everything is fine. I've included code and endpoint output in sections below.

After upgrade

Code:

app.register(require("fastify-metrics"), {
    prefix: 'app_', // this no longer works. I failed to find an equivalent for this
    routeBlacklist: [
        `/internal/metrics`,
        `/internal/health/readiness`
    ]
})

Endpoint output:

# HELP nodejs_version_info Node.js version info.
# TYPE nodejs_version_info gauge
nodejs_version_info{version="v16.15.0",major="16",minor="15",patch="0"} 1

Before upgrade

Code:

app.register(require("fastify-metrics"), {
    prefix: 'app_',
    blacklist: [
        `/internal/metrics`,
        `/internal/health/readiness`
    ],
    enableDefaultMetrics: true,
    enableRouteMetrics: true
})

Endpoint output:

# HELP nodejs_version_info Node.js version info.
# TYPE nodejs_version_info gauge
app_nodejs_version_info{version="v16.15.0",major="16",minor="15",patch="0"} 1

Passed `registry` loses its prototype

After this line

const extendedOpts = merge<MetricConfig>(opts, metrics);

opts.histogram.registers[0] instanceof client.Registry // true
extendedOpts.histogram.registers[0] instanceof client.Registry // false

This leads to

TypeError: registryInstance.registerMetric is not a function
    at /Users/simen/repos/monorepo/node_modules/prom-client/lib/histogram.js:77:26
    at Array.forEach (<anonymous>)
    at new Histogram (/Users/simen/repos/monorepo/node_modules/prom-client/lib/histogram.js:73:20)
    at fastifyMetrics (/Users/simen/repos/monorepo/node_modules/fastify-metrics/dist/index.js:64:27)
    at Plugin.exec (/Users/simen/repos/monorepo/node_modules/avvio/plugin.js:129:17)
    at Boot.loadPlugin (/Users/simen/repos/monorepo/node_modules/avvio/plugin.js:263:10)
    at Task.release (/Users/simen/repos/monorepo/node_modules/fastq/queue.js:140:16)
    at worked (/Users/simen/repos/monorepo/node_modules/fastq/queue.js:182:10)
    at /Users/simen/repos/monorepo/node_modules/avvio/plugin.js:266:7
    at done (/Users/simen/repos/monorepo/node_modules/avvio/plugin.js:198:5)
    at check (/Users/simen/repos/monorepo/node_modules/avvio/plugin.js:222:9)
    at internal/process/task_queues.js:153:7
    at AsyncResource.runInAsyncScope (async_hooks.js:186:9)
    at AsyncResource.runMicrotask (internal/process/task_queues.js:150:8)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)

High cardinality of labels in prometheus metrics - fastify-metrics v6.x

Is there a way to enable some sort of heuristic for grouping labels or manually specifying routes because with default configuration, my metrics is becoming too big? It has records for each possibly route /api/v1/projects/{id}.

For version 6.x.

Here are the records just for 2 requests - /api/v1/projects/2 and /api/v1/projects/3.

http_request_duration_seconds_bucket{le="0.05",method="GET",route="/GET/api/v1/projects/2",status_code="404"} 1
http_request_duration_seconds_bucket{le="0.1",method="GET",route="/GET/api/v1/projects/2",status_code="404"} 1
http_request_duration_seconds_bucket{le="0.5",method="GET",route="/GET/api/v1/projects/2",status_code="404"} 1
http_request_duration_seconds_bucket{le="1",method="GET",route="/GET/api/v1/projects/2",status_code="404"} 1
http_request_duration_seconds_bucket{le="3",method="GET",route="/GET/api/v1/projects/2",status_code="404"} 1
http_request_duration_seconds_bucket{le="5",method="GET",route="/GET/api/v1/projects/2",status_code="404"} 1
http_request_duration_seconds_bucket{le="10",method="GET",route="/GET/api/v1/projects/2",status_code="404"} 1
http_request_duration_seconds_bucket{le="+Inf",method="GET",route="/GET/api/v1/projects/2",status_code="404"} 1
http_request_duration_seconds_sum{method="GET",route="/GET/api/v1/projects/2",status_code="404"} 0.000185834
http_request_duration_seconds_count{method="GET",route="/GET/api/v1/projects/2",status_code="404"} 1
http_request_duration_seconds_bucket{le="0.05",method="GET",route="/GET/api/v1/projects/3",status_code="404"} 1
http_request_duration_seconds_bucket{le="0.1",method="GET",route="/GET/api/v1/projects/3",status_code="404"} 1
http_request_duration_seconds_bucket{le="0.5",method="GET",route="/GET/api/v1/projects/3",status_code="404"} 1
http_request_duration_seconds_bucket{le="1",method="GET",route="/GET/api/v1/projects/3",status_code="404"} 1
http_request_duration_seconds_bucket{le="3",method="GET",route="/GET/api/v1/projects/3",status_code="404"} 1
http_request_duration_seconds_bucket{le="5",method="GET",route="/GET/api/v1/projects/3",status_code="404"} 1
http_request_duration_seconds_bucket{le="10",method="GET",route="/GET/api/v1/projects/3",status_code="404"} 1
http_request_duration_seconds_bucket{le="+Inf",method="GET",route="/GET/api/v1/projects/3",status_code="404"} 1

Thank you!

Docs for custom metrics

Hi, thanks for your amazing repo!

I would like to gather some custom metrics but I didn't find some tests that describe this kind of feature. Is it possible to add a custom gauge to prom-client. If yes, how?

I can send you a PR if needed.

Performance optimizations

Having encountered performance degradation after introducing fastify-metrics, we've attempted doing some of the obvious performance optimizations.

Here are the results (benchmarks included):
kibertoad/fastify-prometheus-nitro#1

I'm not sending PR as-is because it is pretty intrusive, but I can replicate same or all of it in original repo if perf increase seems significant enough for you, and changes acceptable.

Route pattern for monitoring

I'm trying to use route patterns for monitoring (as it's a Prometheus metrics labels best practice) but I cannot find an option to use the route pattern instead of its values. This is an example of what I'm trying to achieve:

-http_request_duration_seconds_bucket{le="0.005",method="GET",route="/jobs/Op4X46WTqqnCKWgV4q",status_code="404"} 0
+http_request_duration_seconds_bucket{le="0.005",method="GET",route="/jobs/:id",status_code="404"} 0

I'd like to use the url defined when registering a new fastify route, e.g:

  fastify.route({
    method: 'GET',
    url: '/jobs/:id',
    handler: handlers.getIds(),
  });

These are the versions I'm using:

fastify-metrics: ^8.0.0
fastify: ^3.6.0

Is there any way I can configure this?

Custom labels

Only a predefined set of labels is supported: method, status and route.
Sometimes it would be useful to support "custom" labels set, so that we could:

  • Decorate a request with the info we want to get from the label.
  • Get the info from the request to populate the custom label.

This would allow to support more fine-grained metrics.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.