From f9cd63724cbd5e5a17978e2a5a9085b49a535779 Mon Sep 17 00:00:00 2001 From: Kamil Kisiela Date: Fri, 25 Nov 2022 09:40:38 +0100 Subject: [PATCH] Introduce tokens_http_requests and usage_tokens_duration_seconds metrics (#684) --- packages/services/tokens/src/api.ts | 23 ++++++++++++++++++++++- packages/services/usage/src/index.ts | 13 ++++++++++++- packages/services/usage/src/metrics.ts | 6 ++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/services/tokens/src/api.ts b/packages/services/tokens/src/api.ts index eef83e470..07750e9a6 100644 --- a/packages/services/tokens/src/api.ts +++ b/packages/services/tokens/src/api.ts @@ -1,4 +1,4 @@ -import { createErrorHandler } from '@hive/service-common'; +import { createErrorHandler, metrics } from '@hive/service-common'; import * as trpc from '@trpc/server'; import { inferProcedureInput, inferProcedureOutput } from '@trpc/server'; import type { FastifyLoggerInstance } from 'fastify'; @@ -7,6 +7,18 @@ import { useCache } from './cache'; import { createHash } from 'crypto'; import { Lru as LruType } from 'tiny-lru'; +const httpRequests = new metrics.Counter({ + name: 'tokens_http_requests', + help: 'Number of http requests', + labelNames: ['path'], +}); + +const httpRequestDuration = new metrics.Histogram({ + name: 'tokens_http_request_duration_seconds', + help: 'Duration of an http request', + labelNames: ['path'], +}); + const TARGET_VALIDATION = z .object({ targetId: z.string().nonempty(), @@ -72,6 +84,15 @@ export type Context = { export const tokensApiRouter = trpc .router() + .middleware(async ({ path, next }) => { + const stopTimer = httpRequestDuration.startTimer({ path }); + httpRequests.inc({ path }); + try { + return await next(); + } finally { + stopTimer(); + } + }) .query('targetTokens', { input: TARGET_VALIDATION, async resolve({ ctx, input }) { diff --git a/packages/services/usage/src/index.ts b/packages/services/usage/src/index.ts index 6386b37ea..926fc2ea7 100644 --- a/packages/services/usage/src/index.ts +++ b/packages/services/usage/src/index.ts @@ -15,6 +15,7 @@ import { httpRequestsWithNoAccess, collectDuration, droppedReports, + tokensDuration, } from './metrics'; import type { IncomingLegacyReport, IncomingReport } from './types'; import { createUsageRateLimit } from './rate-limit'; @@ -96,11 +97,14 @@ async function main() { return; } + const stopTokensDurationTimer = tokensDuration.startTimer(); const tokenInfo = await tokens.fetch(token); - const maskedToken = maskToken(token); if (tokens.isNotFound(tokenInfo)) { + stopTokensDurationTimer({ + status: 'not_found', + }); httpRequestsWithNonExistingToken.inc(); req.log.info('Token not found (token=%s)', maskedToken); res.status(400).send('Missing token'); // eslint-disable-line @typescript-eslint/no-floating-promises -- false positive, FastifyReply.then returns void @@ -109,12 +113,19 @@ async function main() { // We treat collected operations as part of registry if (tokens.isNoAccess(tokenInfo)) { + stopTokensDurationTimer({ + status: 'no_access', + }); httpRequestsWithNoAccess.inc(); req.log.info('No access (token=%s)', maskedToken); res.status(403).send('No access'); // eslint-disable-line @typescript-eslint/no-floating-promises -- false positive, FastifyReply.then returns void return; } + stopTokensDurationTimer({ + status: 'success', + }); + if ( await rateLimit?.isRateLimited({ id: tokenInfo.target, diff --git a/packages/services/usage/src/metrics.ts b/packages/services/usage/src/metrics.ts index 4c1fad374..58df3bcc4 100644 --- a/packages/services/usage/src/metrics.ts +++ b/packages/services/usage/src/metrics.ts @@ -10,6 +10,12 @@ export const tokenRequests = new metrics.Counter({ help: 'Number of requests to Tokens service', }); +export const tokensDuration = new metrics.Histogram({ + name: 'usage_tokens_duration_seconds', + help: 'Duration of an HTTP Request to Tokens service in seconds', + labelNames: ['status'], +}); + export const httpRequests = new metrics.Counter({ name: 'usage_http_requests', help: 'Number of http requests',