hardware details

This commit is contained in:
Alex Holliday committed 2026-01-14 19:28:17 +00:00
1 parent d1faeab042
commit 665eb9a67f
25 files changed
+4050 -590

No files matched your search

@@ -34,9 +34,8 @@ const { compile } = pkg;
import mjml2html from "mjml";
import jwt from "jsonwebtoken";
import crypto from "crypto";
import { games } from "gamedig";
import { games, GameDig } from "gamedig";
import jmespath from "jmespath";
import { GameDig } from "gamedig";
import { fileURLToPath } from "url";
import { ObjectId } from "mongodb";
@@ -47,7 +46,6 @@ import { GenerateAvatarImage } from "../utils/imageProcessing.js";
import { ParseBoolean } from "../utils/utils.js";
// Models
import { CheckModel } from "@/db/models/index.js";
import Monitor from "../db/models/Monitor.js";
import User from "../db/models/User.js";
import InviteToken from "../db/models/InviteToken.js";
@@ -72,11 +70,11 @@ import SettingsModule from "../db/modules/settingsModule.js";
import IncidentModule from "../db/modules/incidentModule.js";
// repositories
import { MongoMonitorsRepository, MongoChecksRepository } from "@/repositories/index.js";
import { MongoMonitorsRepository, MongoChecksRepository, MongoMonitorStatsRepository } from "@/repositories/index.js";
export const initializeServices = async ({ logger, envSettings, settingsService }) => {
export const initializeServices = async ({ logger, envSettings, settingsService }: { logger: any; envSettings: any; settingsService: any }) => {
const serviceRegistry = new ServiceRegistry({ logger });
ServiceRegistry.instance = serviceRegistry;
(ServiceRegistry as any).instance = serviceRegistry;
const translationService = new TranslationService(logger);
await translationService.initialize();
@@ -84,7 +82,7 @@ export const initializeServices = async ({ logger, envSettings, settingsService
const stringService = new StringService(translationService);
// Create DB
const checkModule = new CheckModule({ logger, CheckModel, Monitor, User });
const checkModule = new CheckModule({ logger, Monitor, User });
const inviteModule = new InviteModule({ InviteToken, crypto, stringService });
const statusPageModule = new StatusPageModule({ StatusPage, NormalizeData, stringService });
const userModule = new UserModule({ User, Team, GenerateAvatarImage, ParseBoolean, stringService });
@@ -125,6 +123,7 @@ export const initializeServices = async ({ logger, envSettings, settingsService
// Repositories
const monitorsRepository = new MongoMonitorsRepository();
const checksRepository = new MongoChecksRepository();
const monitorStatsRepository = new MongoMonitorStatsRepository();
const networkService = new NetworkService({
axios,
@@ -228,6 +227,7 @@ export const initializeServices = async ({ logger, envSettings, settingsService
games,
monitorsRepository,
checksRepository,
monitorStatsRepository,
});
const services = {
@@ -8,8 +8,6 @@ import {
createMonitorBodyValidation,
editMonitorBodyValidation,
pauseMonitorParamValidation,
getMonitorStatsByIdParamValidation,
getMonitorStatsByIdQueryValidation,
getCertificateParamValidation,
getHardwareDetailsByIdParamValidation,
getHardwareDetailsByIdQueryValidation,
@@ -90,39 +88,6 @@ class MonitorController {
}
};
getMonitorStatsById = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMonitorStatsByIdParamValidation.validateAsync(req.params);
await getMonitorStatsByIdQueryValidation.validateAsync(req.query);
let { limit, sortOrder, dateRange, numToDisplay, normalize } = req.query;
const monitorId = req?.params?.monitorId;
const teamId = req?.user?.teamId;
if (!teamId) {
throw new AppError({ message: "Team ID is required", status: 400 });
}
const monitorStats = await this.monitorService.getMonitorStatsById({
teamId,
monitorId,
limit,
sortOrder,
dateRange,
numToDisplay,
normalize,
});
return res.status(200).json({
success: true,
msg: "Monitor stats retrieved successfully",
data: monitorStats,
});
} catch (error) {
next(error);
}
};
getHardwareDetailsById = async (req: Request, res: Response, next: NextFunction) => {
try {
await getHardwareDetailsByIdParamValidation.validateAsync(req.params);
-6
View File
@@ -11,12 +11,9 @@ class MongoDB {
inviteModule,
statusPageModule,
userModule,
hardwareCheckModule,
maintenanceWindowModule,
monitorModule,
networkCheckModule,
notificationModule,
pageSpeedCheckModule,
recoveryModule,
settingsModule,
incidentModule,
@@ -26,15 +23,12 @@ class MongoDB {
this.userModule = userModule;
this.inviteModule = inviteModule;
this.recoveryModule = recoveryModule;
this.pageSpeedCheckModule = pageSpeedCheckModule;
this.hardwareCheckModule = hardwareCheckModule;
this.checkModule = checkModule;
this.maintenanceWindowModule = maintenanceWindowModule;
this.monitorModule = monitorModule;
this.notificationModule = notificationModule;
this.settingsModule = settingsModule;
this.statusPageModule = statusPageModule;
this.networkCheckModule = networkCheckModule;
this.incidentModule = incidentModule;
}
-49
View File
@@ -1,49 +0,0 @@
import mongoose from "mongoose";
const MonitorStatsSchema = new mongoose.Schema(
{
monitorId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Monitor",
immutable: true,
index: true,
},
avgResponseTime: {
type: Number,
default: 0,
},
totalChecks: {
type: Number,
default: 0,
},
totalUpChecks: {
type: Number,
default: 0,
},
totalDownChecks: {
type: Number,
default: 0,
},
uptimePercentage: {
type: Number,
default: 0,
},
lastCheckTimestamp: {
type: Number,
default: 0,
},
lastResponseTime: {
type: Number,
default: 0,
},
timeOfLastFailure: {
type: Number,
default: 0,
},
},
{ timestamps: true }
);
const MonitorStats = mongoose.model("MonitorStats", MonitorStatsSchema);
export default MonitorStats;
+63
View File
@@ -0,0 +1,63 @@
import { Schema, model, type Types } from "mongoose";
import type { MonitorStats as MonitorStatsEntity } from "@/types/monitorStats.js";
type MonitorStatsDocumentBase = Omit<MonitorStatsEntity, "id" | "monitorId" | "createdAt" | "updatedAt"> & {
monitorId: Types.ObjectId;
};
interface MonitorStatsDocument extends MonitorStatsDocumentBase {
_id: Types.ObjectId;
createdAt: Date;
updatedAt: Date;
}
const MonitorStatsSchema = new Schema<MonitorStatsDocument>(
{
monitorId: {
type: Schema.Types.ObjectId,
ref: "Monitor",
immutable: true,
index: true,
required: true,
},
avgResponseTime: {
type: Number,
default: 0,
},
totalChecks: {
type: Number,
default: 0,
},
totalUpChecks: {
type: Number,
default: 0,
},
totalDownChecks: {
type: Number,
default: 0,
},
uptimePercentage: {
type: Number,
default: 0,
},
lastCheckTimestamp: {
type: Number,
default: 0,
},
lastResponseTime: {
type: Number,
default: 0,
},
timeOfLastFailure: {
type: Number,
default: undefined,
},
},
{ timestamps: true }
);
const MonitorStatsModel = model<MonitorStatsDocument>("MonitorStats", MonitorStatsSchema);
export type { MonitorStatsDocument };
export { MonitorStatsModel };
export default MonitorStatsModel;
+3
View File
@@ -3,3 +3,6 @@ export { default as MonitorModel } from "@/db/models/Monitor.js";
export * from "@/db/models/Check.js";
export { default as CheckModel } from "@/db/models/Check.js";
export * from "@/db/models/MonitorStats.js";
export { default as MonitorStatsModel } from "@/db/models/MonitorStats.js";
-42
View File
@@ -253,48 +253,6 @@ class MonitorModule {
}
};
getMonitorStatsById = async ({ monitorId, sortOrder, dateRange, numToDisplay, normalize }) => {
try {
// Get monitor, if we can't find it, abort with error
const monitor = await this.Monitor.findById(monitorId);
if (monitor === null || monitor === undefined) {
throw new Error(this.stringService.getDbFindMonitorById(monitorId));
}
// Get query params
const sort = sortOrder === "asc" ? 1 : -1;
// Get Checks for monitor in date range requested
const dates = this.getDateRange(dateRange);
const { checksAll, checksForDateRange } = await this.getMonitorChecks(monitorId, dates, sort);
// Build monitor stats
const monitorStats = {
...monitor.toObject(),
uptimeDuration: this.calculateUptimeDuration(checksAll),
lastChecked: this.getLastChecked(checksAll),
latestResponseTime: this.getLatestResponseTime(checksAll),
periodIncidents: this.getIncidents(checksForDateRange),
periodTotalChecks: checksForDateRange.length,
checks: this.processChecksForDisplay(this.NormalizeData, checksForDateRange, numToDisplay, normalize),
};
if (monitor.type === "http" || monitor.type === "ping" || monitor.type === "docker" || monitor.type === "port" || monitor.type === "game") {
// HTTP/PING Specific stats
monitorStats.periodAvgResponseTime = this.getAverageResponseTime(checksForDateRange);
monitorStats.periodUptime = this.getUptimePercentage(checksForDateRange);
const groupedChecks = this.groupChecksByTime(checksForDateRange, dateRange);
monitorStats.aggregateData = Object.values(groupedChecks).map(this.calculateGroupStats);
}
return monitorStats;
} catch (error) {
error.service = SERVICE_NAME;
error.method = "getMonitorStatsById";
throw error;
}
};
getHardwareDetailsById = async ({ monitorId, dateRange }) => {
try {
const monitor = await this.Monitor.findById(monitorId);
@@ -1,3 +1,4 @@
import type { Check, MonitorType } from "@/types/index.js";
import type { LatestChecksMap } from "@/repositories/checks/MongoChecksRepistory.js";
export interface IChecksRepository {
@@ -6,12 +7,53 @@ export interface IChecksRepository {
monitorId: string,
startDate: Date,
endDate: Date,
dateString: string
): Promise<{
groupedChecks: Array<{ _id: string; avgResponseTime: number; totalChecks: number }>;
groupedUpChecks: Array<{ _id: string; totalChecks: number; avgResponseTime: number }>;
groupedDownChecks: Array<{ _id: string; totalChecks: number; avgResponseTime: number }>;
uptimePercentage: number;
avgResponseTime: number;
}>;
dateString: string,
options?: { type?: MonitorType }
): Promise<
| {
monitorType: "uptime";
groupedChecks: Array<{ _id: string; avgResponseTime: number; totalChecks: number }>;
groupedUpChecks: Array<{ _id: string; totalChecks: number; avgResponseTime: number }>;
groupedDownChecks: Array<{ _id: string; totalChecks: number; avgResponseTime: number }>;
uptimePercentage: number;
avgResponseTime: number;
}
| {
monitorType: "hardware";
aggregateData: {
latestCheck: Check | null;
totalChecks: number;
};
upChecks: {
totalChecks: number;
};
checks: Array<{
_id: string;
avgCpuUsage: number;
avgMemoryUsage: number;
avgTemperature: number[];
disks: Array<{
name: string;
readSpeed: number;
writeSpeed: number;
totalBytes: number;
freeBytes: number;
usagePercent: number;
}>;
net: Array<{
name: string;
bytesSentPerSecond: number;
deltaBytesRecv: number;
deltaPacketsSent: number;
deltaPacketsRecv: number;
deltaErrIn: number;
deltaErrOut: number;
deltaDropIn: number;
deltaDropOut: number;
deltaFifoIn: number;
deltaFifoOut: number;
}>;
}>;
}
>;
}
@@ -14,6 +14,11 @@ import type {
} from "@/types/index.js";
import { CheckModel, type CheckDocument } from "@/db/models/index.js";
import mongoose from "mongoose";
import {
getAggregateData as getHardwareAggregateData,
getHardwareStats,
getUpChecks as getHardwareUpChecks,
} from "@/db/modules/monitorModuleQueries.js";
export type LatestChecksMap = Record<string, Check[]>;
@@ -210,20 +215,17 @@ class MongoChecksRepistory implements IChecksRepository {
}, {});
};
findDateRangeChecksByMonitor = async (
monitorId: string,
startDate: Date,
endDate: Date,
dateString: string
): Promise<{
groupedChecks: Array<{ _id: string; avgResponseTime: number; totalChecks: number }>;
groupedUpChecks: Array<{ _id: string; totalChecks: number; avgResponseTime: number }>;
groupedDownChecks: Array<{ _id: string; totalChecks: number; avgResponseTime: number }>;
uptimePercentage: number;
avgResponseTime: number;
}> => {
findDateRangeChecksByMonitor = async (monitorId: string, startDate: Date, endDate: Date, dateString: string, options?: { type?: string }) => {
const monitorObjectId = new mongoose.Types.ObjectId(monitorId);
if (options?.type === "hardware") {
return this.findHardwareDateRangeChecks(monitorObjectId, startDate, endDate, dateString);
}
return this.findUptimeDateRangeChecks(monitorObjectId, startDate, endDate, dateString);
};
private findUptimeDateRangeChecks = async (monitorObjectId: mongoose.Types.ObjectId, startDate: Date, endDate: Date, dateString: string) => {
const matchStage = {
"metadata.monitorId": new mongoose.Types.ObjectId(monitorId),
"metadata.monitorId": monitorObjectId,
updatedAt: { $gte: startDate, $lte: endDate },
};
const [result] = await CheckModel.aggregate([
@@ -296,12 +298,13 @@ class MongoChecksRepistory implements IChecksRepository {
],
},
},
]).exec();
]);
const uptimePercentage = result?.uptimePercentage?.[0]?.percentage ?? 0;
const avgResponseTime = result?.groupedAvgResponseTime?.[0]?.avgResponseTime ?? 0;
return {
monitorType: "uptime" as const,
groupedChecks: result?.groupedChecks ?? [],
groupedUpChecks: result?.groupedUpChecks ?? [],
groupedDownChecks: result?.groupedDownChecks ?? [],
@@ -309,6 +312,60 @@ class MongoChecksRepistory implements IChecksRepository {
avgResponseTime,
};
};
private findHardwareDateRangeChecks = async (monitorObjectId: mongoose.Types.ObjectId, startDate: Date, endDate: Date, dateString: string) => {
const monitorId = monitorObjectId.toHexString();
const dates = { start: startDate, end: endDate };
const [aggregateDataDoc, upChecksDoc, hardwareMetrics] = await Promise.all([
getHardwareAggregateData(monitorId, dates),
getHardwareUpChecks(monitorId, dates),
getHardwareStats(monitorId, dates, dateString),
]);
const aggregateData = {
latestCheck: aggregateDataDoc?.latestCheck ? this.toEntity(aggregateDataDoc.latestCheck as CheckDocument) : null,
totalChecks: aggregateDataDoc?.totalChecks ?? 0,
};
const upChecks = {
totalChecks: upChecksDoc?.totalChecks ?? 0,
};
const checks = (hardwareMetrics ?? []).map((metric) => ({
_id: metric._id,
avgCpuUsage: metric.avgCpuUsage ?? 0,
avgMemoryUsage: metric.avgMemoryUsage ?? 0,
avgTemperature: metric.avgTemperature ?? [],
disks: (metric.disks ?? []).map((disk: { [key: string]: number | string | undefined }) => ({
name: disk?.name ?? "",
readSpeed: disk?.readSpeed ?? 0,
writeSpeed: disk?.writeSpeed ?? 0,
totalBytes: disk?.totalBytes ?? 0,
freeBytes: disk?.freeBytes ?? 0,
usagePercent: disk?.usagePercent ?? 0,
})),
net: (metric.net ?? []).map((iface: { [key: string]: number | string | undefined }) => ({
name: iface?.name ?? "",
bytesSentPerSecond: iface?.bytesSentPerSecond ?? 0,
deltaBytesRecv: iface?.deltaBytesRecv ?? 0,
deltaPacketsSent: iface?.deltaPacketsSent ?? 0,
deltaPacketsRecv: iface?.deltaPacketsRecv ?? 0,
deltaErrIn: iface?.deltaErrIn ?? 0,
deltaErrOut: iface?.deltaErrOut ?? 0,
deltaDropIn: iface?.deltaDropIn ?? 0,
deltaDropOut: iface?.deltaDropOut ?? 0,
deltaFifoIn: iface?.deltaFifoIn ?? 0,
deltaFifoOut: iface?.deltaFifoOut ?? 0,
})),
}));
return {
monitorType: "hardware" as const,
aggregateData,
upChecks,
checks,
};
};
}
export default MongoChecksRepistory;
+3
View File
@@ -3,3 +3,6 @@ export { default as MongoMonitorsRepository } from "@/repositories/monitors/Mong
export * from "@/repositories/checks/IChecksRepository.js";
export { default as MongoChecksRepository } from "@/repositories/checks/MongoChecksRepistory.js";
export * from "@/repositories/monitor-stats/IMonitorStatsRepository.js";
export { default as MongoMonitorStatsRepository } from "@/repositories/monitor-stats/MongoMonitorStatsRepository.js";
@@ -0,0 +1,9 @@
import type { MonitorStats } from "@/types/index.js";
export interface IMonitorStatsRepository {
// create
// single fetch
findByMonitorId(monitorId: string): Promise<MonitorStats>;
// update
// delete
// other
}
@@ -0,0 +1,44 @@
import { type MonitorStatsDocument, MonitorStatsModel } from "@/db/models/index.js";
import type { MonitorStats } from "@/types/index.js";
import { IMonitorStatsRepository } from "@/repositories/index.js";
import mongoose from "mongoose";
import { AppError } from "@/utils/AppError.js";
class MongoMonitorStatsRepository implements IMonitorStatsRepository {
private toEntity = (doc: MonitorStatsDocument): MonitorStats => {
const toStringId = (value: unknown): string => {
if (value instanceof mongoose.Types.ObjectId) {
return value.toString();
}
return value?.toString() ?? "";
};
const toDateString = (value: Date | string): string => {
return value instanceof Date ? value.toISOString() : value;
};
return {
id: toStringId(doc._id),
monitorId: toStringId(doc.monitorId),
avgResponseTime: doc.avgResponseTime,
totalChecks: doc.totalChecks,
totalUpChecks: doc.totalUpChecks,
totalDownChecks: doc.totalDownChecks,
uptimePercentage: doc.uptimePercentage,
lastCheckTimestamp: doc.lastCheckTimestamp,
lastResponseTime: doc.lastResponseTime,
timeOfLastFailure: doc.timeOfLastFailure,
createdAt: toDateString(doc.createdAt),
updatedAt: toDateString(doc.updatedAt),
};
};
findByMonitorId = async (monitorId: string): Promise<MonitorStats> => {
const monitorStats = await MonitorStatsModel.findOne({ monitorId: new mongoose.Types.ObjectId(monitorId) });
if (!monitorStats) {
throw new AppError({ message: "Monitor stats not found", status: 404 });
}
return this.toEntity(monitorStats);
};
}
export default MongoMonitorStatsRepository;
-1
View File
@@ -30,7 +30,6 @@ class MonitorRoutes {
// General monitor routes
this.router.post("/pause/:monitorId", isAllowed(["admin", "superadmin"]), this.monitorController.pauseMonitor);
this.router.get("/stats/:monitorId", this.monitorController.getMonitorStatsById);
// Util routes
this.router.get("/certificate/:monitorId", (req, res, next) => {
+41 -49
View File
@@ -2,7 +2,7 @@ import { createMonitorsBodyValidation } from "@/validation/joi.js";
import { NormalizeData, NormalizeDataUptimeDetails } from "@/utils/dataUtils.js";
import { type Monitor } from "@/types/index.js";
import type { MonitorType } from "@/types/monitor.js";
import type { IChecksRepository, IMonitorsRepository } from "@/repositories/index.js";
import type { IChecksRepository, IMonitorsRepository, IMonitorStatsRepository } from "@/repositories/index.js";
import fs from "fs";
import { fileURLToPath } from "url";
import path from "path";
@@ -23,17 +23,8 @@ export interface IMonitorService {
// read
getUptimeDetailsById(args: { teamId: string; monitorId: string; dateRange: string; normalize?: boolean }): Promise<any>;
getMonitorStatsById(args: {
teamId: string;
monitorId: string;
limit?: number;
sortOrder?: 1 | -1;
dateRange?: string;
numToDisplay?: number;
normalize?: boolean;
}): Promise<any>;
getHardwareDetailsById(args: { teamId: string; monitorId: string; dateRange: string }): Promise<any>;
getMonitorById(args: { teamId: string; monitorId: string }): Promise<any>;
getMonitorById(args: { teamId: string; monitorId: string }): Promise<Monitor>;
getMonitorsByTeamId(args: {
teamId: string;
limit?: number;
@@ -86,7 +77,7 @@ export class MonitorService implements IMonitorService {
private games: any;
private monitorsRepository: IMonitorsRepository;
private checksRepository: IChecksRepository;
private fs: any;
private monitorStatsRepository: IMonitorStatsRepository;
constructor({
db,
@@ -99,6 +90,7 @@ export class MonitorService implements IMonitorService {
games,
monitorsRepository,
checksRepository,
monitorStatsRepository,
}: {
db: any;
jobQueue: any;
@@ -110,6 +102,7 @@ export class MonitorService implements IMonitorService {
games: any;
monitorsRepository: IMonitorsRepository;
checksRepository: IChecksRepository;
monitorStatsRepository: IMonitorStatsRepository;
}) {
this.db = db;
this.jobQueue = jobQueue;
@@ -121,6 +114,7 @@ export class MonitorService implements IMonitorService {
this.games = games;
this.monitorsRepository = monitorsRepository;
this.checksRepository = checksRepository;
this.monitorStatsRepository = monitorStatsRepository;
}
get serviceName(): string {
@@ -269,10 +263,14 @@ export class MonitorService implements IMonitorService {
}
const rangeKey = (dateRange as DateRangeKey) ?? "recent";
const { start, end } = this.getDateRange(rangeKey);
const checksData = await this.checksRepository.findDateRangeChecksByMonitor(monitor.id, start, end, this.getDateFormat(rangeKey));
const monitorStats = await this.db.monitorModule.getMonitorStatsById({
monitorId,
const checksData = await this.checksRepository.findDateRangeChecksByMonitor(monitor.id, start, end, this.getDateFormat(rangeKey), {
type: monitor.type,
});
const monitorStats = await this.monitorStatsRepository.findByMonitorId(monitor.id);
if (checksData.monitorType !== "uptime") {
throw new AppError({ message: `${monitor.type} monitors are not supported for uptime details`, status: 400 });
}
return {
monitorData: {
@@ -287,47 +285,41 @@ export class MonitorService implements IMonitorService {
};
};
getMonitorStatsById = async ({
teamId,
monitorId,
limit,
sortOrder,
dateRange,
numToDisplay,
normalize,
}: {
teamId: string;
monitorId: string;
limit?: number;
sortOrder?: 1 | -1;
dateRange?: string;
numToDisplay?: number;
normalize?: boolean;
}): Promise<any> => {
await this.verifyTeamAccess({ teamId, monitorId });
const monitorStats = await this.db.monitorModule.getMonitorStatsById({
monitorId,
limit,
sortOrder,
dateRange,
numToDisplay,
normalize,
});
return monitorStats;
};
getHardwareDetailsById = async ({ teamId, monitorId, dateRange }: { teamId: string; monitorId: string; dateRange: string }): Promise<any> => {
await this.verifyTeamAccess({ teamId, monitorId });
const monitor = await this.db.monitorModule.getHardwareDetailsById({ monitorId, dateRange });
const monitor = await this.monitorsRepository.findById(monitorId, teamId);
if (!monitor) {
throw new AppError({ message: `Monitor with ID ${monitorId} not found.`, status: 404 });
}
if (monitor.type !== "hardware") {
throw new AppError({ message: `${monitor.type} monitors are not supported for hardware details`, status: 400 });
}
return monitor;
const rangeKey = (dateRange as DateRangeKey) ?? "recent";
const { start, end } = this.getDateRange(rangeKey);
const checksData = await this.checksRepository.findDateRangeChecksByMonitor(monitor.id, start, end, this.getDateFormat(rangeKey), {
type: monitor.type,
});
if (checksData.monitorType !== "hardware") {
throw new AppError({ message: "Unable to load hardware stats for this monitor", status: 500 });
}
const stats = {
aggregateData: checksData.aggregateData,
upChecks: checksData.upChecks,
checks: checksData.checks,
};
return {
...monitor,
stats,
};
};
getMonitorById = async ({ teamId, monitorId }: { teamId: string; monitorId: string }): Promise<any> => {
await this.verifyTeamAccess({ teamId, monitorId });
const monitor = await this.db.monitorModule.getMonitorById(monitorId);
const monitor = await this.monitorsRepository.findById(monitorId, teamId);
return monitor;
};
@@ -7,10 +7,14 @@ class StatusService {
/**
* @param {{
* db: any
* logger: any
* buffer: import("./bufferService.js").BufferService
* incidentService: import("../business/incidentService.js").IncidentService
* monitorsRepository: any
* }}
*/ constructor({ db, logger, buffer, incidentService, monitorsRepository }) {
*/
constructor({ db, logger, buffer, incidentService, monitorsRepository }) {
this.db = db;
this.logger = logger;
this.buffer = buffer;
+1
View File
@@ -1,2 +1,3 @@
export * from "@/types/check.js";
export * from "@/types/monitor.js";
export * from "@/types/monitorStats.js";
+14
View File
@@ -0,0 +1,14 @@
export interface MonitorStats {
id: string;
monitorId: string;
avgResponseTime: number;
totalChecks: number;
totalUpChecks: number;
totalDownChecks: number;
uptimePercentage: number;
lastCheckTimestamp: number;
lastResponseTime: number;
timeOfLastFailure?: number;
createdAt: string;
updatedAt: string;
}
-14
View File
@@ -134,18 +134,6 @@ const getMonitorsByTeamIdQueryValidation = joi.object({
order: joi.string().valid("asc", "desc"),
});
const getMonitorStatsByIdParamValidation = joi.object({
monitorId: joi.string().required(),
});
const getMonitorStatsByIdQueryValidation = joi.object({
status: joi.string(),
limit: joi.number(),
sortOrder: joi.string().valid("asc", "desc"),
dateRange: joi.string().valid("hour", "day", "week", "month", "all"),
numToDisplay: joi.number(),
normalize: joi.boolean(),
});
const getCertificateParamValidation = joi.object({
monitorId: joi.string().required(),
});
@@ -725,8 +713,6 @@ export {
getMonitorByIdQueryValidation,
getMonitorsByTeamIdParamValidation,
getMonitorsByTeamIdQueryValidation,
getMonitorStatsByIdParamValidation,
getMonitorStatsByIdQueryValidation,
getHardwareDetailsByIdParamValidation,
getHardwareDetailsByIdQueryValidation,
getCertificateParamValidation,