mirror of
https://github.com/graphql-hive/console
synced 2026-05-23 17:18:23 +00:00
Introduce tokens_http_requests and usage_tokens_duration_seconds metrics (#684)
This commit is contained in:
parent
91be8c994a
commit
f9cd63724c
3 changed files with 40 additions and 2 deletions
|
|
@ -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<Context>()
|
||||
.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 }) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
Loading…
Reference in a new issue