174 lines
4.1 KiB
TypeScript
174 lines
4.1 KiB
TypeScript
// src/services/host-monitor.ts
|
|
// Copyright (C) 2025 DTP Technologies, LLC
|
|
// All Rights Reserved
|
|
|
|
import env from "../config/env.js";
|
|
|
|
import os from "node:os";
|
|
import v8 from "node:v8";
|
|
import { EventEmitter } from "node:events";
|
|
|
|
import { CronJob } from "cron";
|
|
|
|
import HostMonitor, { IHostMonitor } from "@/models/host-monitor.js";
|
|
import { DtpService } from "../lib/service.js";
|
|
|
|
export interface IHostMonitorStats {
|
|
memoryUtilization: number;
|
|
rss: number;
|
|
heapTotal: number;
|
|
heapUsed: number;
|
|
heapExternal: number;
|
|
osTotal: number;
|
|
osFree: number;
|
|
timestamp: Date;
|
|
}
|
|
|
|
class HostMonitorService extends DtpService {
|
|
private cronJob: CronJob | undefined;
|
|
private stats: IHostMonitor;
|
|
private eventEmitter: EventEmitter;
|
|
|
|
get name(): string {
|
|
return "HostMonitorService";
|
|
}
|
|
get slug(): string {
|
|
return "search";
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
this.stats = this.createMonitor();
|
|
this.stats.hostname = os.hostname();
|
|
this.eventEmitter = new EventEmitter();
|
|
}
|
|
|
|
async start(): Promise<void> {
|
|
const { heap_size_limit } = v8.getHeapStatistics();
|
|
const limitMB = (heap_size_limit / 1024 / 1024).toFixed(2);
|
|
|
|
this.log.info("starting host monitor cron job");
|
|
this.cronJob = new CronJob(
|
|
"*/15 * * * * *",
|
|
this.onStoreStats.bind(this),
|
|
null,
|
|
true,
|
|
env.timezone,
|
|
);
|
|
|
|
this.log.info("service started", { heapLimit: limitMB });
|
|
}
|
|
|
|
async stop(): Promise<void> {
|
|
if (this.cronJob) {
|
|
this.log.info("stopping host monitor cron job");
|
|
this.cronJob.stop();
|
|
delete this.cronJob;
|
|
}
|
|
|
|
this.log.info("service stopped");
|
|
}
|
|
|
|
subagent(bytes: number): void {
|
|
this.stats.memory.ai.subagents.count += 1;
|
|
this.stats.memory.ai.subagents.bytes += bytes;
|
|
}
|
|
|
|
fileOperation(bytes: number): void {
|
|
this.stats.memory.ai.fileOperations.count += 1;
|
|
this.stats.memory.ai.fileOperations.bytes += bytes;
|
|
}
|
|
|
|
toolCall(bytes: number): void {
|
|
this.stats.memory.ai.toolCalls.count += 1;
|
|
this.stats.memory.ai.toolCalls.bytes += bytes;
|
|
}
|
|
|
|
on(event: string, listener: (...args: any[]) => void): void {
|
|
this.eventEmitter.on(event, listener);
|
|
}
|
|
|
|
off(event: string, listener: (...args: any[]) => void): void {
|
|
this.eventEmitter.off(event, listener);
|
|
}
|
|
|
|
async onStoreStats(): Promise<void> {
|
|
const NOW = new Date();
|
|
this.stats.timestamp = NOW;
|
|
|
|
const usage: NodeJS.MemoryUsage = process.memoryUsage();
|
|
this.stats.memory.rss = usage.rss;
|
|
this.stats.memory.v8.heapTotal = usage.heapTotal;
|
|
this.stats.memory.v8.heapUsed = usage.heapUsed;
|
|
this.stats.memory.v8.heapExternal = usage.external ?? 0;
|
|
|
|
const osTotal = os.totalmem();
|
|
const osFree = os.freemem();
|
|
this.stats.memory.os.total = osTotal;
|
|
this.stats.memory.os.free = osFree;
|
|
|
|
// store stats to db
|
|
await this.stats.save();
|
|
|
|
// Calculate memory utilization percentage
|
|
const memoryUsed = osTotal - osFree;
|
|
const memoryUtilization = Math.round((memoryUsed / osTotal) * 100);
|
|
|
|
// Emit stats event for UI updates
|
|
const statsData: IHostMonitorStats = {
|
|
memoryUtilization,
|
|
rss: usage.rss,
|
|
heapTotal: usage.heapTotal,
|
|
heapUsed: usage.heapUsed,
|
|
heapExternal: usage.external ?? 0,
|
|
osTotal,
|
|
osFree,
|
|
timestamp: NOW,
|
|
};
|
|
this.eventEmitter.emit("stats", statsData);
|
|
|
|
this.stats = this.createMonitor();
|
|
}
|
|
|
|
createMonitor(): IHostMonitor {
|
|
const monitor = new HostMonitor();
|
|
monitor.hostname = os.hostname();
|
|
|
|
const usage = process.memoryUsage();
|
|
monitor.memory = {
|
|
rss: usage.rss,
|
|
os: {
|
|
total: os.totalmem(),
|
|
free: os.freemem(),
|
|
},
|
|
v8: {
|
|
heapTotal: usage.heapTotal,
|
|
heapUsed: usage.heapUsed,
|
|
heapExternal: usage.external ?? 0,
|
|
},
|
|
logs: {
|
|
count: 0,
|
|
bytes: 0,
|
|
},
|
|
ai: {
|
|
fileOperations: {
|
|
count: 0,
|
|
bytes: 0,
|
|
},
|
|
subagents: {
|
|
count: 0,
|
|
bytes: 0,
|
|
},
|
|
toolCalls: {
|
|
count: 0,
|
|
bytes: 0,
|
|
},
|
|
},
|
|
};
|
|
|
|
return monitor;
|
|
}
|
|
}
|
|
|
|
export default new HostMonitorService();
|