telex-server-monitor-sdk
Version:
SDK for Telex Server Monitor - A lightweight agent that collects and reports server CPU metrics to the Telex monitoring platform
137 lines (136 loc) • 5.3 kB
JavaScript
import { logger } from "../utils/logger.js";
import { getStoreData, saveStoreData } from "../utils/store.js";
import { CollectorService } from "../metrics/collector.js";
import { connectToIntegrationServer, closeSocket, sendCpuAlert, } from "../services/zeromqService.js";
import os from "os";
let cpuCheckInterval = null;
// Track last alert time to prevent alert spam
let lastAlertTime = {};
/**
* Start the monitoring process
*/
export async function startMonitoring() {
try {
if (getStoreData()?.isMonitoringRunning) {
logger.warn("Monitoring is already running");
return;
}
const storeData = getStoreData();
const channelId = storeData?.outputChannelId;
if (!channelId) {
throw new Error("No channel ID found. Please run setup first.");
}
// Save hostname as server name if not already set
if (!storeData?.serverName) {
try {
const hostname = os.hostname();
saveStoreData({ serverName: hostname });
logger.info(`Server name set to hostname: ${hostname}`);
}
catch (error) {
logger.warn(`Could not get hostname: ${error.message}`);
saveStoreData({ serverName: "Unknown Server" });
}
}
logger.info(`Starting monitoring with channel ID: ${channelId}`);
logger.info("Connecting to integration server to receive metric requests");
// Connect to the integration server
await connectToIntegrationServer(channelId);
saveStoreData({ isMonitoringRunning: true });
// Start periodic CPU monitoring
startCpuMonitoring(channelId);
// Keep the process running
process.on("SIGINT", async () => {
await stopMonitoring();
process.exit(0);
});
process.on("SIGTERM", async () => {
await stopMonitoring();
process.exit(0);
});
}
catch (error) {
logger.error(`Failed to start monitoring: ${error.message}`);
saveStoreData({ isMonitoringRunning: false });
closeSocket();
throw error;
}
}
/**
* Start periodic CPU monitoring
*/
function startCpuMonitoring(channelId) {
if (cpuCheckInterval) {
clearInterval(cpuCheckInterval);
}
logger.info("Starting CPU threshold monitoring");
// Reset alert tracking
lastAlertTime = {};
cpuCheckInterval = setInterval(async () => {
try {
const metrics = await CollectorService.getMetrics();
const storeData = getStoreData();
const threshold = storeData?.cpuThreshold || 80;
const currentTime = Date.now();
// Only send alerts if CPU usage is above threshold
if (metrics.cpu && metrics.cpu.usage > threshold) {
// Determine alert severity
const isCritical = metrics.cpu.usage > threshold + 10;
// Only send alerts if it has been more than 5 minutes since the last alert of the same severity
// This prevents alert flooding
const alertKey = isCritical ? "critical" : "warning";
const cooldownPeriod = 5 * 60 * 1000; // 5 minutes in ms
if (!lastAlertTime[alertKey] ||
currentTime - lastAlertTime[alertKey] > cooldownPeriod) {
// Log and send the alert
if (isCritical) {
logger.error(`CRITICAL: CPU usage at ${metrics.cpu.usage.toFixed(1)}%, exceeding threshold of ${threshold}%`);
}
else {
logger.warn(`WARNING: CPU usage at ${metrics.cpu.usage.toFixed(1)}%, exceeding threshold of ${threshold}%`);
}
// Send alert via ZeroMQ
await sendCpuAlert(channelId, metrics, threshold, isCritical);
// Update last alert time
lastAlertTime[alertKey] = currentTime;
}
else {
logger.info(`Suppressing ${alertKey} CPU alert (${metrics.cpu.usage.toFixed(1)}%) - cooldown period active`);
}
}
}
catch (error) {
logger.error(`Error in CPU monitoring: ${error.message}`);
}
}, 60000); // Check every minute
logger.info("CPU monitoring interval started - checking every minute");
}
/**
* Stop the monitoring process
*/
export async function stopMonitoring() {
if (!getStoreData()?.isMonitoringRunning) {
logger.warn("Monitoring is not running");
return;
}
try {
if (cpuCheckInterval) {
clearInterval(cpuCheckInterval);
cpuCheckInterval = null;
logger.info("CPU monitoring stopped");
}
closeSocket();
saveStoreData({ isMonitoringRunning: false });
logger.info("Monitoring stopped successfully");
}
catch (error) {
logger.error(`Failed to stop monitoring: ${error.message}`);
throw error;
}
}
/**
* Check if monitoring is currently running
*/
export function isMonitoringRunning() {
return getStoreData()?.isMonitoringRunning || false;
}