You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

117 lines
3.3 KiB

#!/usr/bin/env node
// Agent Health Monitor for OpenClaw
// Monitors agent crashes, errors, and service health
// Sends notifications via configured channels (Telegram, etc.)
const fs = require('fs');
const path = require('path');
class AgentHealthMonitor {
constructor() {
this.config = this.loadConfig();
this.logDir = '/root/.openclaw/workspace/logs/agents';
this.ensureLogDir();
}
loadConfig() {
try {
const configPath = '/root/.openclaw/openclaw.json';
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
} catch (error) {
console.error('Failed to load OpenClaw config:', error);
return {};
}
}
ensureLogDir() {
if (!fs.existsSync(this.logDir)) {
fs.mkdirSync(this.logDir, { recursive: true });
}
}
async sendNotification(message, severity = 'error') {
// Log to file first
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] [${severity.toUpperCase()}] ${message}\n`;
const logFile = path.join(this.logDir, `health-${new Date().toISOString().split('T')[0]}.log`);
fs.appendFileSync(logFile, logEntry);
// Send via Telegram if configured
if (this.config.channels?.telegram?.enabled) {
await this.sendTelegramNotification(message, severity);
}
}
async sendTelegramNotification(message, severity) {
const botToken = this.config.channels.telegram.botToken;
const chatId = '5237946060'; // Your Telegram ID
if (!botToken) {
console.error('Telegram bot token not configured');
return;
}
try {
const url = `https://api.telegram.org/bot${botToken}/sendMessage`;
const payload = {
chat_id: chatId,
text: `🚨 OpenClaw Agent Alert (${severity})\n\n${message}`,
parse_mode: 'Markdown'
};
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!response.ok) {
console.error('Failed to send Telegram notification:', await response.text());
}
} catch (error) {
console.error('Telegram notification error:', error);
}
}
monitorProcess(processName, checkFunction) {
// Set up process monitoring
process.on('uncaughtException', async (error) => {
await this.sendNotification(
`Uncaught exception in ${processName}:\n${error.stack || error.message}`,
'critical'
);
process.exit(1);
});
process.on('unhandledRejection', async (reason, promise) => {
await this.sendNotification(
`Unhandled rejection in ${processName}:\nReason: ${reason}\nPromise: ${promise}`,
'error'
);
});
// Custom health check
if (checkFunction) {
setInterval(async () => {
try {
const isHealthy = await checkFunction();
if (!isHealthy) {
await this.sendNotification(
`${processName} health check failed`,
'warning'
);
}
} catch (error) {
await this.sendNotification(
`${processName} health check error: ${error.message}`,
'error'
);
}
}, 30000); // Check every 30 seconds
}
}
}
module.exports = AgentHealthMonitor;