diff --git a/packages/services/usage/src/index.ts b/packages/services/usage/src/index.ts index f8e13606a4..70f6aad547 100644 --- a/packages/services/usage/src/index.ts +++ b/packages/services/usage/src/index.ts @@ -12,6 +12,8 @@ import { env } from './environment'; import { collectDuration, droppedReports, + httpRequestDuration, + httpRequestHandlerDuration, httpRequests, httpRequestsWithNoAccess, httpRequestsWithNonExistingToken, @@ -26,6 +28,12 @@ import { createUsage } from './usage'; import { usageProcessorV1 } from './usage-processor-1'; import { usageProcessorV2 } from './usage-processor-2'; +declare module 'fastify' { + interface FastifyRequest { + onRequestHRTime: [number, number]; + } +} + async function main() { if (env.sentry) { Sentry.init({ @@ -84,12 +92,26 @@ async function main() { }, ); - server.route<{ - Body: unknown; - }>({ + server.route< + { + Body: unknown; + }, + { + onRequestTime: number; + } + >({ method: 'POST', url: '/', - async handler(req, res) { + onRequest(req, _, done) { + req.onRequestHRTime = process.hrtime(); + done(); + }, + onResponse(req, _, done) { + const delta = process.hrtime(req.onRequestHRTime); + httpRequestDuration.observe(delta[0] + delta[1] / 1e9); + done(); + }, + handler: measureHandler(async function usageHandler(req, res) { httpRequests.inc(); let token: string | undefined; const legacyToken = req.headers['x-api-token'] as string; @@ -102,8 +124,9 @@ async function main() { usedAPIVersion.labels({ version: '1' }).inc(); } else if (apiVersion === '2') { usedAPIVersion.labels({ version: '2' }).inc(); + } else { + usedAPIVersion.labels({ version: 'invalid' }).inc(); } - usedAPIVersion.labels({ version: 'invalid' }).inc(); } else { usedAPIVersion.labels({ version: 'none' }).inc(); } @@ -285,7 +308,7 @@ async function main() { }); void res.status(500).send(); } - }, + }), }); server.route({ @@ -343,3 +366,15 @@ function measureParsing(fn: () => T, version: 'v1' | 'v2'): T { stop(); } } + +function measureHandler<$Req, $Res>(fn: (_req: $Req, _res: $Res) => Promise) { + return async function (req: $Req, res: $Res) { + const stop = httpRequestHandlerDuration.startTimer(); + + try { + await fn(req, res); + } finally { + stop(); + } + }; +} diff --git a/packages/services/usage/src/metrics.ts b/packages/services/usage/src/metrics.ts index 499d867497..57d51bcfac 100644 --- a/packages/services/usage/src/metrics.ts +++ b/packages/services/usage/src/metrics.ts @@ -22,6 +22,16 @@ export const httpRequests = new metrics.Counter({ help: 'Number of http requests', }); +export const httpRequestDuration = new metrics.Histogram({ + name: 'usage_http_request_duration_seconds', + help: 'Duration of an HTTP Request in seconds', +}); + +export const httpRequestHandlerDuration = new metrics.Histogram({ + name: 'usage_http_request_handler_duration_seconds', + help: 'Duration of an HTTP Request handler in seconds', +}); + export const httpRequestsWithoutToken = new metrics.Counter({ name: 'usage_http_requests_no_token', help: 'Number of http requests without a token',