mirror of
https://github.com/movie-web/backend.git
synced 2025-09-13 10:43:25 +00:00
added user metrics
This commit is contained in:
@@ -21,8 +21,8 @@ Backend for movie-web
|
||||
- [ ] consume provider metrics
|
||||
- [ ] DELETE user - should delete all associated data
|
||||
- [ ] prometheus metrics
|
||||
- [ ] requests
|
||||
- [ ] user count
|
||||
- [X] requests
|
||||
- [X] user count
|
||||
- [ ] provider metrics
|
||||
- [ ] ratelimits (stored in redis)
|
||||
- [X] switch to pnpm
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { setupFastify } from '@/modules/fastify';
|
||||
import { setupFastify, startFastify } from '@/modules/fastify';
|
||||
import { setupMetrics } from '@/modules/metrics';
|
||||
import { setupMikroORM } from '@/modules/mikro';
|
||||
import { scopedLogger } from '@/services/logger';
|
||||
|
||||
@@ -9,8 +10,11 @@ async function bootstrap(): Promise<void> {
|
||||
evt: 'setup',
|
||||
});
|
||||
|
||||
const app = await setupFastify();
|
||||
await setupMikroORM();
|
||||
await setupFastify();
|
||||
await setupMetrics(app);
|
||||
|
||||
await startFastify(app);
|
||||
|
||||
log.info(`App setup, ready to accept connections`, {
|
||||
evt: 'success',
|
||||
|
@@ -72,9 +72,14 @@ export async function setupFastify(): Promise<FastifyInstance> {
|
||||
},
|
||||
);
|
||||
|
||||
if (!exportedApp) throw new Error('no app to export in fastify');
|
||||
return exportedApp;
|
||||
}
|
||||
|
||||
export function startFastify(app: FastifyInstance) {
|
||||
// listen to port
|
||||
log.info(`listening to port`, { evt: 'setup-listen' });
|
||||
return new Promise((resolve) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
app.listen(
|
||||
{
|
||||
port: conf.server.port,
|
||||
@@ -91,7 +96,7 @@ export async function setupFastify(): Promise<FastifyInstance> {
|
||||
log.info(`fastify setup successfully`, {
|
||||
evt: 'setup-success',
|
||||
});
|
||||
resolve(exportedApp as FastifyInstance);
|
||||
resolve();
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@@ -9,11 +9,8 @@ import { userProgressRouter } from '@/routes/users/progress';
|
||||
import { userSessionsRouter } from '@/routes/users/sessions';
|
||||
import { userSettingsRouter } from '@/routes/users/settings';
|
||||
import { FastifyInstance } from 'fastify';
|
||||
import metricsPlugin from 'fastify-metrics';
|
||||
|
||||
export async function setupRoutes(app: FastifyInstance) {
|
||||
await app.register(metricsPlugin, { endpoint: '/metrics' });
|
||||
|
||||
await app.register(manageAuthRouter.register);
|
||||
await app.register(loginAuthRouter.register);
|
||||
await app.register(userSessionsRouter.register);
|
||||
|
39
src/modules/metrics/index.ts
Normal file
39
src/modules/metrics/index.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { getORM } from '@/modules/mikro';
|
||||
import { FastifyInstance } from 'fastify';
|
||||
import { Counter } from 'prom-client';
|
||||
import metricsPlugin from 'fastify-metrics';
|
||||
import { updateMetrics } from '@/modules/metrics/update';
|
||||
import { scopedLogger } from '@/services/logger';
|
||||
|
||||
const log = scopedLogger('metrics');
|
||||
|
||||
export type Metrics = {
|
||||
user: Counter<'namespace'>;
|
||||
};
|
||||
|
||||
let metrics: null | Metrics = null;
|
||||
|
||||
export function getMetrics() {
|
||||
if (!metrics) throw new Error('metrics not initialized');
|
||||
return metrics;
|
||||
}
|
||||
|
||||
export async function setupMetrics(app: FastifyInstance) {
|
||||
log.info(`Setting up metrics...`, { evt: 'start' });
|
||||
|
||||
await app.register(metricsPlugin, { endpoint: '/metrics' });
|
||||
|
||||
metrics = {
|
||||
user: new Counter({
|
||||
name: 'user_count',
|
||||
help: 'user_help',
|
||||
labelNames: ['namespace'],
|
||||
}),
|
||||
};
|
||||
|
||||
const orm = getORM();
|
||||
const em = orm.em.fork();
|
||||
log.info(`Syncing up metrics...`, { evt: 'sync' });
|
||||
await updateMetrics(em, metrics);
|
||||
log.info(`Metrics initialized!`, { evt: 'end' });
|
||||
}
|
22
src/modules/metrics/update.ts
Normal file
22
src/modules/metrics/update.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { User } from '@/db/models/User';
|
||||
import { Metrics } from '@/modules/metrics';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
|
||||
export async function updateMetrics(em: EntityManager, metrics: Metrics) {
|
||||
const users = await em
|
||||
.createQueryBuilder(User)
|
||||
.groupBy('namespace')
|
||||
.count()
|
||||
.select(['namespace', 'count'])
|
||||
.execute<
|
||||
{
|
||||
namespace: string;
|
||||
count: string;
|
||||
}[]
|
||||
>();
|
||||
|
||||
metrics.user.reset();
|
||||
users.forEach((v) => {
|
||||
metrics?.user.inc({ namespace: v.namespace }, Number(v.count));
|
||||
});
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
import { formatSession } from '@/db/models/Session';
|
||||
import { User, formatUser } from '@/db/models/User';
|
||||
import { getMetrics } from '@/modules/metrics';
|
||||
import { assertCaptcha } from '@/services/captcha';
|
||||
import { handle } from '@/services/handler';
|
||||
import { makeRouter } from '@/services/router';
|
||||
@@ -37,6 +38,7 @@ export const manageAuthRouter = makeRouter((app) => {
|
||||
);
|
||||
|
||||
await em.persistAndFlush([user, session]);
|
||||
getMetrics().user.inc({ namespace: body.namespace }, 1);
|
||||
|
||||
return {
|
||||
user: formatUser(user),
|
||||
|
Reference in New Issue
Block a user