add mongo stats to diagnostic service
This commit is contained in:
1 parent
2764468e90
commit
2d432e0a3d
4 files changed
+127
-49
No files matched your search
@@ -121,7 +121,7 @@ import {
|
||||
IMaintenanceWindowsRepository,
|
||||
} from "@/repositories/index.js";
|
||||
import { ILogger } from "@/utils/logger.js";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
// import { AppError } from "@/utils/AppError.js";
|
||||
|
||||
export type InitializedServices = {
|
||||
settingsService: ISettingsService;
|
||||
@@ -173,55 +173,76 @@ export const initializeServices = async ({
|
||||
}): Promise<InitializedServices> => {
|
||||
// Create DB
|
||||
|
||||
const dbType = envSettings.dbType;
|
||||
|
||||
let db: IDb | null = null;
|
||||
|
||||
if (dbType === "mongodb") {
|
||||
db = new MongoDB(logger, envSettings);
|
||||
}
|
||||
|
||||
if (!db) {
|
||||
throw new AppError({ message: "Unsupported database type", status: 500 });
|
||||
}
|
||||
|
||||
db = new MongoDB(logger, envSettings);
|
||||
await db.connect();
|
||||
|
||||
let monitorsRepository: IMonitorsRepository;
|
||||
let checksRepository: IChecksRepository;
|
||||
let geoChecksRepository: IGeoChecksRepository;
|
||||
let monitorStatsRepository: IMonitorStatsRepository;
|
||||
let statusPagesRepository: IStatusPagesRepository;
|
||||
let usersRepository: IUsersRepository;
|
||||
let invitesRepository: IInvitesRepository;
|
||||
let recoveryTokensRepository: IRecoveryTokensRepository;
|
||||
let settingsRepository: ISettingsRepository;
|
||||
let notificationsRepository: INotificationsRepository;
|
||||
let tagsRepository: ITagsRepository;
|
||||
let incidentsRepository: IIncidentsRepository;
|
||||
let teamsRepository: ITeamsRepository;
|
||||
let maintenanceWindowsRepository: IMaintenanceWindowsRepository;
|
||||
// ** NOTE **
|
||||
// const dbType = envSettings.dbType;
|
||||
// DB type has been fixed to MongoDB for now
|
||||
|
||||
// if (dbType === "mongodb") {
|
||||
// db = new MongoDB(logger, envSettings);
|
||||
// }
|
||||
|
||||
// if (!db) {
|
||||
// throw new AppError({ message: "Unsupported database type", status: 500 });
|
||||
// }
|
||||
|
||||
// await db.connect();
|
||||
|
||||
// Repositories
|
||||
|
||||
if (dbType === "mongodb") {
|
||||
monitorsRepository = new MongoMonitorsRepository();
|
||||
checksRepository = new MongoChecksRepository(logger);
|
||||
geoChecksRepository = new MongoGeoChecksRepository(logger);
|
||||
monitorStatsRepository = new MongoMonitorStatsRepository();
|
||||
statusPagesRepository = new MongoStatusPagesRepository();
|
||||
usersRepository = new MongoUsersRepository();
|
||||
invitesRepository = new MongoInvitesRepository();
|
||||
recoveryTokensRepository = new MongoRecoveryTokensRepository();
|
||||
settingsRepository = new MongoSettingsRepository();
|
||||
notificationsRepository = new MongoNotificationsRepository();
|
||||
tagsRepository = new MongoTagsRepository();
|
||||
incidentsRepository = new MongoIncidentsRepository();
|
||||
teamsRepository = new MongoTeamsRepository();
|
||||
maintenanceWindowsRepository = new MongoMaintenanceWindowsRepository();
|
||||
} else {
|
||||
throw new AppError({ message: "Unsupported database type", status: 500 });
|
||||
}
|
||||
// ** NOTE **
|
||||
// DB Type fixed to MongoDB for now
|
||||
// let monitorsRepository: IMonitorsRepository;
|
||||
// let checksRepository: IChecksRepository;
|
||||
// let geoChecksRepository: IGeoChecksRepository;
|
||||
// let monitorStatsRepository: IMonitorStatsRepository;
|
||||
// let statusPagesRepository: IStatusPagesRepository;
|
||||
// let usersRepository: IUsersRepository;
|
||||
// let invitesRepository: IInvitesRepository;
|
||||
// let recoveryTokensRepository: IRecoveryTokensRepository;
|
||||
// let settingsRepository: ISettingsRepository;
|
||||
// let notificationsRepository: INotificationsRepository;
|
||||
// let tagsRepository: ITagsRepository;
|
||||
// let incidentsRepository: IIncidentsRepository;
|
||||
// let teamsRepository: ITeamsRepository;
|
||||
// let maintenanceWindowsRepository: IMaintenanceWindowsRepository;
|
||||
|
||||
// if (dbType === "mongodb") {
|
||||
// monitorsRepository = new MongoMonitorsRepository();
|
||||
// checksRepository = new MongoChecksRepository(logger);
|
||||
// geoChecksRepository = new MongoGeoChecksRepository(logger);
|
||||
// monitorStatsRepository = new MongoMonitorStatsRepository();
|
||||
// statusPagesRepository = new MongoStatusPagesRepository();
|
||||
// usersRepository = new MongoUsersRepository();
|
||||
// invitesRepository = new MongoInvitesRepository();
|
||||
// recoveryTokensRepository = new MongoRecoveryTokensRepository();
|
||||
// settingsRepository = new MongoSettingsRepository();
|
||||
// notificationsRepository = new MongoNotificationsRepository();
|
||||
// tagsRepository = new MongoTagsRepository();
|
||||
// incidentsRepository = new MongoIncidentsRepository();
|
||||
// teamsRepository = new MongoTeamsRepository();
|
||||
// maintenanceWindowsRepository = new MongoMaintenanceWindowsRepository();
|
||||
// } else {
|
||||
// throw new AppError({ message: "Unsupported database type", status: 500 });
|
||||
// }
|
||||
|
||||
const monitorsRepository = new MongoMonitorsRepository();
|
||||
const checksRepository = new MongoChecksRepository(logger);
|
||||
const geoChecksRepository = new MongoGeoChecksRepository(logger);
|
||||
const monitorStatsRepository = new MongoMonitorStatsRepository();
|
||||
const statusPagesRepository = new MongoStatusPagesRepository();
|
||||
const usersRepository = new MongoUsersRepository();
|
||||
const invitesRepository = new MongoInvitesRepository();
|
||||
const recoveryTokensRepository = new MongoRecoveryTokensRepository();
|
||||
const settingsRepository = new MongoSettingsRepository();
|
||||
const notificationsRepository = new MongoNotificationsRepository();
|
||||
const tagsRepository = new MongoTagsRepository();
|
||||
const incidentsRepository = new MongoIncidentsRepository();
|
||||
const teamsRepository = new MongoTeamsRepository();
|
||||
const maintenanceWindowsRepository = new MongoMaintenanceWindowsRepository();
|
||||
|
||||
// Inject settings repository into settings service (now that DB is connected)
|
||||
(settingsService as SettingsService).setRepository(settingsRepository);
|
||||
@@ -340,7 +361,7 @@ export const initializeServices = async ({
|
||||
teamsRepository,
|
||||
});
|
||||
|
||||
const diagnosticService = new DiagnosticService();
|
||||
const diagnosticService = new DiagnosticService(db);
|
||||
const inviteService = new InviteService({
|
||||
invitesRepository,
|
||||
settingsService,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export interface IDb {
|
||||
export interface IDb<TConnection = unknown> {
|
||||
connect(): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
getConnection(): Promise<TConnection>;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Mongoose } from "mongoose";
|
||||
import mongoose from "mongoose";
|
||||
import AppSettings from "@/db/models/AppSettings.js";
|
||||
import { runMigrations } from "@/db/migration/index.js";
|
||||
@@ -5,16 +6,19 @@ import { ILogger } from "@/utils/logger.js";
|
||||
import { EnvConfig } from "@/service/system/settingsService.js";
|
||||
const SERVICE_NAME = "MongoDB";
|
||||
import { IDb } from "@/db/IDb.js";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
|
||||
class MongoDB implements IDb {
|
||||
class MongoDB implements IDb<Mongoose> {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
private logger: ILogger;
|
||||
private envSettings: EnvConfig;
|
||||
private db: Mongoose | null;
|
||||
|
||||
constructor(logger: ILogger, envSettings: EnvConfig) {
|
||||
this.logger = logger;
|
||||
this.envSettings = envSettings;
|
||||
this.db = null;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
@@ -24,7 +28,7 @@ class MongoDB implements IDb {
|
||||
connect = async () => {
|
||||
try {
|
||||
const connectionString = this.envSettings.dbConnectionString || "mongodb://localhost:27017/uptime_db";
|
||||
await mongoose.connect(connectionString);
|
||||
this.db = await mongoose.connect(connectionString);
|
||||
// If there are no AppSettings, create one // TODO why is this here?
|
||||
await AppSettings.findOneAndUpdate(
|
||||
{}, // empty filter to match any document
|
||||
@@ -63,6 +67,13 @@ class MongoDB implements IDb {
|
||||
}
|
||||
};
|
||||
|
||||
getConnection = async (): Promise<Mongoose> => {
|
||||
if (this.db === null) {
|
||||
throw new AppError({ message: "Database not connected", service: SERVICE_NAME, method: "getConnection" });
|
||||
}
|
||||
return this.db;
|
||||
};
|
||||
|
||||
disconnect = async () => {
|
||||
try {
|
||||
this.logger.info({ message: "Disconnecting from MongoDB", service: SERVICE_NAME, method: "disconnect" });
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import v8 from "v8";
|
||||
import os from "os";
|
||||
import { IDb } from "@/db/IDb.js";
|
||||
import { Mongoose } from "mongoose";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
|
||||
const SERVICE_NAME = "diagnosticService";
|
||||
|
||||
@@ -18,7 +21,7 @@ export interface IDiagnosticService {
|
||||
export class DiagnosticService implements IDiagnosticService {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
constructor() {
|
||||
constructor(private db: IDb<Mongoose>) {
|
||||
/**
|
||||
* Performance Observer for monitoring system performance metrics.
|
||||
* Clears performance marks after each measurement to prevent memory leaks.
|
||||
@@ -47,6 +50,44 @@ export class DiagnosticService implements IDiagnosticService {
|
||||
return cpuUsage;
|
||||
};
|
||||
|
||||
private getMongoDBStats = async () => {
|
||||
const mongo = await this.db.getConnection();
|
||||
const db = mongo.connection.db;
|
||||
if (!db) {
|
||||
throw new AppError({ message: "Database connection is not available", service: SERVICE_NAME, method: "getMongoDBStats" });
|
||||
}
|
||||
|
||||
const readyState = mongo.connection.readyState;
|
||||
const host = mongo.connection.host;
|
||||
const port = mongo.connection.port;
|
||||
const dbName = mongo.connection.name;
|
||||
|
||||
const serverStatus = await db.admin().serverStatus();
|
||||
const serverInfo = await db.admin().serverInfo();
|
||||
|
||||
const stats = await db.stats();
|
||||
const collections = await db.collections();
|
||||
|
||||
const collectionStats = await Promise.all(
|
||||
(collections || []).map(async (collection) => {
|
||||
const stats = await db.command({ collStats: collection.collectionName });
|
||||
const documentCount = await db.collection(collection.collectionName).countDocuments({});
|
||||
return { name: collection.collectionName, documentCount, ...stats };
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
readyState,
|
||||
host,
|
||||
port,
|
||||
dbName,
|
||||
serverStatus,
|
||||
serverInfo,
|
||||
stats,
|
||||
collectionStats,
|
||||
};
|
||||
};
|
||||
|
||||
getSystemStats = async () => {
|
||||
// Memory Usage
|
||||
const totalMemory = os.totalmem();
|
||||
@@ -93,6 +134,9 @@ export class DiagnosticService implements IDiagnosticService {
|
||||
// Uptime
|
||||
const uptimeMs = process.uptime() * 1000; // ms
|
||||
|
||||
// Mongo
|
||||
const mongoStats = await this.getMongoDBStats();
|
||||
|
||||
// Combine Metrics
|
||||
const diagnostics = {
|
||||
osStats,
|
||||
@@ -101,6 +145,7 @@ export class DiagnosticService implements IDiagnosticService {
|
||||
v8HeapStats: v8Metrics,
|
||||
eventLoopDelayMs: eventLoopDelay,
|
||||
uptimeMs,
|
||||
mongoStats,
|
||||
};
|
||||
|
||||
return diagnostics;
|
||||
|
||||
Reference in new issue
Block a user