mirror of
https://github.com/movie-web/backend.git
synced 2025-09-13 13:03:26 +00:00
added user metrics
This commit is contained in:
@@ -21,8 +21,8 @@ Backend for movie-web
|
|||||||
- [ ] consume provider metrics
|
- [ ] consume provider metrics
|
||||||
- [ ] DELETE user - should delete all associated data
|
- [ ] DELETE user - should delete all associated data
|
||||||
- [ ] prometheus metrics
|
- [ ] prometheus metrics
|
||||||
- [ ] requests
|
- [X] requests
|
||||||
- [ ] user count
|
- [X] user count
|
||||||
- [ ] provider metrics
|
- [ ] provider metrics
|
||||||
- [ ] ratelimits (stored in redis)
|
- [ ] ratelimits (stored in redis)
|
||||||
- [X] switch to pnpm
|
- [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 { setupMikroORM } from '@/modules/mikro';
|
||||||
import { scopedLogger } from '@/services/logger';
|
import { scopedLogger } from '@/services/logger';
|
||||||
|
|
||||||
@@ -9,8 +10,11 @@ async function bootstrap(): Promise<void> {
|
|||||||
evt: 'setup',
|
evt: 'setup',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const app = await setupFastify();
|
||||||
await setupMikroORM();
|
await setupMikroORM();
|
||||||
await setupFastify();
|
await setupMetrics(app);
|
||||||
|
|
||||||
|
await startFastify(app);
|
||||||
|
|
||||||
log.info(`App setup, ready to accept connections`, {
|
log.info(`App setup, ready to accept connections`, {
|
||||||
evt: 'success',
|
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
|
// listen to port
|
||||||
log.info(`listening to port`, { evt: 'setup-listen' });
|
log.info(`listening to port`, { evt: 'setup-listen' });
|
||||||
return new Promise((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
app.listen(
|
app.listen(
|
||||||
{
|
{
|
||||||
port: conf.server.port,
|
port: conf.server.port,
|
||||||
@@ -91,7 +96,7 @@ export async function setupFastify(): Promise<FastifyInstance> {
|
|||||||
log.info(`fastify setup successfully`, {
|
log.info(`fastify setup successfully`, {
|
||||||
evt: 'setup-success',
|
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 { userSessionsRouter } from '@/routes/users/sessions';
|
||||||
import { userSettingsRouter } from '@/routes/users/settings';
|
import { userSettingsRouter } from '@/routes/users/settings';
|
||||||
import { FastifyInstance } from 'fastify';
|
import { FastifyInstance } from 'fastify';
|
||||||
import metricsPlugin from 'fastify-metrics';
|
|
||||||
|
|
||||||
export async function setupRoutes(app: FastifyInstance) {
|
export async function setupRoutes(app: FastifyInstance) {
|
||||||
await app.register(metricsPlugin, { endpoint: '/metrics' });
|
|
||||||
|
|
||||||
await app.register(manageAuthRouter.register);
|
await app.register(manageAuthRouter.register);
|
||||||
await app.register(loginAuthRouter.register);
|
await app.register(loginAuthRouter.register);
|
||||||
await app.register(userSessionsRouter.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 { formatSession } from '@/db/models/Session';
|
||||||
import { User, formatUser } from '@/db/models/User';
|
import { User, formatUser } from '@/db/models/User';
|
||||||
|
import { getMetrics } from '@/modules/metrics';
|
||||||
import { assertCaptcha } from '@/services/captcha';
|
import { assertCaptcha } from '@/services/captcha';
|
||||||
import { handle } from '@/services/handler';
|
import { handle } from '@/services/handler';
|
||||||
import { makeRouter } from '@/services/router';
|
import { makeRouter } from '@/services/router';
|
||||||
@@ -37,6 +38,7 @@ export const manageAuthRouter = makeRouter((app) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await em.persistAndFlush([user, session]);
|
await em.persistAndFlush([user, session]);
|
||||||
|
getMetrics().user.inc({ namespace: body.namespace }, 1);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: formatUser(user),
|
user: formatUser(user),
|
||||||
|
Reference in New Issue
Block a user