Open Matanelc opened 2 years ago
Hi, sorry for late answer.
Theoretically it's possible, but it will require creating of additional server. However it's easier to do manually. Just set endpoint
param to undefined
value and then you may create additional server which will do the same that's done in https://github.com/SkeLLLa/fastify-metrics/blob/master/src/index.ts#L193.
Another example in case its helpful to anyone. Here is registering the metrics plugin on a main server, and serving up the stats on a different server/port:
import fp from 'fastify-plugin'
import Fastify from 'fastify'
/**
* This plugins adds promethius metrics
*
* @see https://gitlab.com/m03geek/fastify-metrics
*/
export default fp(async function (fastify, opts) {
fastify.register((await import('fastify-metrics')).default, {
defaultMetrics: { enabled: true },
endpoint: null,
name: 'metrics',
routeMetrics: { enabled: true }
})
const promServer = Fastify({
logger: true
})
promServer.route({
url: '/metrics',
method: 'GET',
logLevel: 'info',
schema: {
// hide route from swagger plugins
hide: true
},
handler: async (_, reply) => {
reply.type('text/plain').send(await fastify.metrics.client.register.metrics())
}
})
const start = async () => {
try {
await promServer.listen({
port: 9091,
host: '0.0.0.0'
})
} catch (err) {
promServer.log.error(err)
promServer.log('promethius server stopped')
process.exit(1)
}
}
fastify.addHook('onClose', async (instance) => {
await promServer.close()
})
await start()
},
{
name: 'prom',
dependencies: ['env']
})
Maybe to make this a bit easier we can add export of such object to a var like fastify.metrics.route
{
url: '/metrics',
method: 'GET',
logLevel: 'info',
schema: {
// hide route from swagger plugins
hide: true
},
handler: async (_, reply) => {
reply.type('text/plain').send(await fastify.metrics.client.register.metrics())
}
}
@SkeLLLa Hey! We're also keen to host our metrics from another port, but would like to avoid duplicating too much from this library to do so. Would be happy to look at contributing something for this use case. Given this was last discussed a few years ago, what would your preferred implementation look like?
One option: allow passing an alternate fastify server that the route gets registered to:
const metricsServer = fastify();
await server.register(metricsPlugin, {
endpointServer: metricsServer,
endpoint: {
url: '/metrics',
logLevel: 'warn',
}
});
Another option: allow passing a function for endpoint
param to expose the endpoint yourself:
const metricsServer = fastify();
await server.register(metricsPlugin, {
endpoint: (route) => (
metricsServer.route({
…route,
logLevel: 'warn',
})
);
});
Open to other ideas too 😄
@joeholdcroft I think both options are fine, so if you submitting the PR you can choose one what suites your needs. Might be the first one will be more types-friendly and it will be easier to make that endpoint server optional.
Is this a reasonable solution to this @SkeLLLa? I don't entirely understand how prom-client
and this plugin work under the hood, specifically what is in an instance and what is global. I think I could even skip passing the promClient as an option, since it seems everything is global in that anyway.
import promClient from 'prom-client'
import metricsPlugin from 'fastify-metrics'
const mainServer = createFastify()
const metricsServer = createFastify()
mainServer.register(metricsPlugin, { endpoint: null, promClient })
metricsServer.register(
metricsPlugin,
{
endpoint: '/metrics',
promClient,
defaultMetrics: { enabled: false },
routeMetrics: { enabled: false },
}
)
await mainServer.listen({ port: 8080 })
await metricsServer.listen({ port: 8081 })
)
@gmaclennan I think it's good idea. In prom-client what's global - it's a default global Registry
. So in theory it could even work without passing promClient
to metrics server, since they will share default global registry.
So worth to try the following code:
import promClient from 'prom-client'
import metricsPlugin from 'fastify-metrics'
const mainServer = createFastify()
const metricsServer = createFastify()
mainServer.register(metricsPlugin, { endpoint: null })
metricsServer.register(
metricsPlugin,
{
endpoint: '/metrics',
defaultMetrics: { enabled: false },
routeMetrics: { enabled: false },
}
)
await mainServer.listen({ port: 8080 })
await metricsServer.listen({ port: 8081 })
)
Hi, I would like to know if that possible to expose the metrics to via other port. in express we can do it with https://www.npmjs.com/package/express-prometheus-middleware is there something that we can do with the current plugin ? right now im exposing it on the same port as the app but i understood that this is not the best practice.