Merge pull request #2673 from bluewave-labs/feat/diagnostic-service

feat: diagnostic service
This commit is contained in:
Alexander Holliday authored and GitHub committed 2025-07-23 14:31:51 -07:00
commit 3239f555a1
3 files changed
+134 -75

No files matched your search

+40 -74
View File
@@ -1,84 +1,49 @@
import v8 from "v8";
import os from "os";
import { asyncHandler } from "../utils/errorUtils.js";
const SERVICE_NAME = "diagnosticController";
const obs = new PerformanceObserver((items) => {
const entry = items.getEntries()[0];
performance.clearMarks();
});
obs.observe({ entryTypes: ["measure"] });
/**
* Diagnostic Controller
*
* Handles system diagnostic and monitoring requests including system statistics,
* performance metrics, and health checks.
*
* @class DiagnosticController
* @description Manages system diagnostics and performance monitoring
*/
class DiagnosticController {
constructor(db) {
this.db = db;
/**
* Creates an instance of DiagnosticController.
*
* @param {Object} dependencies - The dependencies required by the controller
* @param {Object} dependencies.diagnosticService - Service for system diagnostics and monitoring
*/
constructor({ diagnosticService }) {
this.diagnosticService = diagnosticService;
}
getCPUUsage = async () => {
const startUsage = process.cpuUsage();
const timingPeriod = 1000; // measured in ms
await new Promise((resolve) => setTimeout(resolve, timingPeriod));
const endUsage = process.cpuUsage(startUsage);
const cpuUsage = {
userUsageMs: endUsage.user / 1000,
systemUsageMs: endUsage.system / 1000,
usagePercentage: ((endUsage.user + endUsage.system) / 1000 / timingPeriod) * 100,
};
return cpuUsage;
};
/**
* Retrieves comprehensive system statistics and performance metrics.
*
* @async
* @function getSystemStats
* @param {Object} req - Express request object
* @param {Object} res - Express response object
* @returns {Promise<Object>} Success response with system diagnostics data
* @description Returns system performance metrics, memory usage, CPU statistics,
* and other diagnostic information useful for monitoring system health.
* @example
* GET /diagnostics/stats
* // Response includes:
* // - Memory usage (heap, external, arrayBuffers)
* // - CPU usage statistics
* // - System uptime
* // - Performance metrics
* // - Database connection status
* // - Active processes/connections
*/
getSystemStats = asyncHandler(
async (req, res, next) => {
// Memory Usage
const totalMemory = os.totalmem();
const freeMemory = os.freemem();
const osStats = {
freeMemoryBytes: freeMemory, // bytes
totalMemoryBytes: totalMemory, // bytes
};
const used = process.memoryUsage();
const memoryUsage = {};
for (let key in used) {
memoryUsage[`${key}Mb`] = Math.round((used[key] / 1024 / 1024) * 100) / 100; // MB
}
// CPU Usage
const cpuMetrics = await this.getCPUUsage();
// V8 Heap Statistics
const heapStats = v8.getHeapStatistics();
const v8Metrics = {
totalHeapSizeBytes: heapStats.total_heap_size, // bytes
usedHeapSizeBytes: heapStats.used_heap_size, // bytes
heapSizeLimitBytes: heapStats.heap_size_limit, // bytes
};
// Event Loop Delay
let eventLoopDelay = 0;
performance.mark("start");
await new Promise((resolve) => setTimeout(resolve, 0));
performance.mark("end");
performance.measure("eventLoopDelay", "start", "end");
const entries = performance.getEntriesByName("eventLoopDelay");
if (entries.length > 0) {
eventLoopDelay = entries[0].duration;
}
// Uptime
const uptimeMs = process.uptime() * 1000; // ms
// Combine Metrics
const diagnostics = {
osStats,
memoryUsage,
cpuUsage: cpuMetrics,
v8HeapStats: v8Metrics,
eventLoopDelayMs: eventLoopDelay,
uptimeMs,
};
async (req, res) => {
const diagnostics = await this.diagnosticService.getSystemStats();
return res.success({
msg: "OK",
data: diagnostics,
@@ -88,4 +53,5 @@ class DiagnosticController {
"getSystemStats"
);
}
export default DiagnosticController;
+5 -1
View File
@@ -60,6 +60,7 @@ import SuperSimpleQueueHelper from "./service/infrastructure/SuperSimpleQueue/Su
// Business services
import UserService from "./service/business/userService.js";
import CheckService from "./service/business/checkService.js";
import DiagnosticService from "./service/business/diagnosticService.js";
//Network service and dependencies
import NetworkService from "./service/infrastructure/networkService.js";
@@ -196,6 +197,7 @@ const startApp = async () => {
settingsService,
stringService,
});
const diagnosticService = new DiagnosticService();
// const jobQueueHelper = new JobQueueHelper({
// redisService,
@@ -328,7 +330,9 @@ const startApp = async () => {
db: ServiceRegistry.get(MongoDB.SERVICE_NAME),
});
const diagnosticController = new DiagnosticController(ServiceRegistry.get(MongoDB.SERVICE_NAME));
const diagnosticController = new DiagnosticController({
diagnosticService,
});
//Create routes
const authRoutes = new AuthRoutes(authController);
@@ -0,0 +1,89 @@
import v8 from "v8";
import os from "os";
const SERVICE_NAME = "diagnosticService";
class DiagnosticService {
static SERVICE_NAME = SERVICE_NAME;
constructor() {
/**
* Performance Observer for monitoring system performance metrics.
* Clears performance marks after each measurement to prevent memory leaks.
*/
const obs = new PerformanceObserver((items) => {
// Get the first entry but we don't need to store it
items.getEntries()[0];
performance.clearMarks();
});
obs.observe({ entryTypes: ["measure"] });
}
getCPUUsage = async () => {
const startUsage = process.cpuUsage();
const timingPeriod = 1000; // measured in ms
await new Promise((resolve) => setTimeout(resolve, timingPeriod));
const endUsage = process.cpuUsage(startUsage);
const cpuUsage = {
userUsageMs: endUsage.user / 1000,
systemUsageMs: endUsage.system / 1000,
usagePercentage: ((endUsage.user + endUsage.system) / 1000 / timingPeriod) * 100,
};
return cpuUsage;
};
getSystemStats = async () => {
// Memory Usage
const totalMemory = os.totalmem();
const freeMemory = os.freemem();
const osStats = {
freeMemoryBytes: freeMemory, // bytes
totalMemoryBytes: totalMemory, // bytes
};
const used = process.memoryUsage();
const memoryUsage = {};
for (let key in used) {
memoryUsage[`${key}Mb`] = Math.round((used[key] / 1024 / 1024) * 100) / 100; // MB
}
// CPU Usage
const cpuMetrics = await this.getCPUUsage();
// V8 Heap Statistics
const heapStats = v8.getHeapStatistics();
const v8Metrics = {
totalHeapSizeBytes: heapStats.total_heap_size, // bytes
usedHeapSizeBytes: heapStats.used_heap_size, // bytes
heapSizeLimitBytes: heapStats.heap_size_limit, // bytes
};
// Event Loop Delay
let eventLoopDelay = 0;
performance.mark("start");
await new Promise((resolve) => setTimeout(resolve, 0));
performance.mark("end");
performance.measure("eventLoopDelay", "start", "end");
const entries = performance.getEntriesByName("eventLoopDelay");
if (entries.length > 0) {
eventLoopDelay = entries[0].duration;
}
// Uptime
const uptimeMs = process.uptime() * 1000; // ms
// Combine Metrics
const diagnostics = {
osStats,
memoryUsage,
cpuUsage: cpuMetrics,
v8HeapStats: v8Metrics,
eventLoopDelayMs: eventLoopDelay,
uptimeMs,
};
return diagnostics;
};
}
export default DiagnosticService;