/** * Monitor via HeroUnion */ import path from 'node:path'; import cron from 'node-cron'; import axios from 'axios'; import common from './lib/common.mjs'; import md5 from 'md5'; class Monitor { //构造函数,设置默认配置 constructor() { this.config = null; //默认配置 this.systemLogDir = 'log/'; //系统日志保存目录 this.reloadConfigFrequence = 5; //单位:分钟,配置重新加载时间间隔 this.monitFrequence = 10; //单位:分钟,检测时间间隔 this.resultQueryFrequence = 1; //单位:分钟,检测任务结果查询时间间隔 this.tasks = []; //HeroUnion检测任务队列 } async getConfig(forceReload) { const _self = this; if ( !this.config || (typeof(forceReload) != 'undefined' && forceReload) ) { let config = await common.getConfigFromJsonFile('config.json'); //覆盖默认配置 for (const key in config) { if (typeof(_self[key]) != 'undefined') { _self[key] = config[key]; } } this.config = config; } return this.config; } //自动重新加载配置文件 autoReloadConfigs() { const _self = this; const frequence = typeof(this.config.reloadConfigFrequence) != 'undefined' && this.config.reloadConfigFrequence ? this.config.reloadConfigFrequence : 5; //5 分钟重新加载一次 const cronjob = cron.schedule(`*/${frequence} * * * *`, () => { const forceReload = true; _self.getConfig(forceReload); }, { scheduled: false }); cronjob.start(); common.log('Cronjob of config auto reload started.'); } //自动向HeroUnion提交检测任务 autoCreateMonitTask() { const _self = this; const frequence = typeof(this.config.monitFrequence) != 'undefined' && this.config.monitFrequence ? this.config.monitFrequence : 10; //10 分钟检测一次 const cronjob = cron.schedule(`*/${frequence} * * * *`, async () => { let configs = await _self.getConfig(); if (configs.monit_urls.length == 0) { console.error("No monit urls"); return false; } let taskRes; let total = configs.monit_urls.length; for (let i=0; i item.url == configs.monit_urls[i] && item.stats != 'done')) {continue;} console.log("Checking url %s ...", configs.monit_urls[i]); taskRes = await common.createHeroUnionTask(configs.monit_urls[i], '', configs); if (taskRes && taskRes.code == 1) { _self.tasks.push(taskRes.task); console.log("Monit task", taskRes.task); }else { console.error("Monit task create failed", taskRes); } } }, { scheduled: false }); cronjob.start(); common.log('Cronjob of url monit started.'); } async queryTasks() { const _self = this; let configs = await _self.getConfig(); console.log('Task number', _self.tasks.length); let task, taskRes; for(let index = 0; index < _self.tasks.length; index ++) { task = _self.tasks[index]; if (task.status == 'done') {continue;} console.log('Query task result', task); taskRes = await common.queryHeroUnionTask(task.id, configs); if (taskRes && taskRes.code == 1) { console.log("Task result", taskRes); _self.tasks[index] = taskRes.task; common.log('Connect success, url: %s, task id: %s', task.url, task.id); let currentTime = common.getLocalTimeString(); let logFile = path.resolve(_self.systemLogDir) + '/ok.log'; common.saveLog(logFile, `[${currentTime}] Url request success: ${task.url}, task id: ${task.id}\n`); }else { console.error("Monit task query failed", taskRes); //TODO: 写入日志,或发送告警 common.error('Connect warning, url: %s, task id: %s', task.url, task.id); let currentTime = common.getLocalTimeString(); let logFile = path.resolve(_self.systemLogDir) + '/fail.log'; common.saveLog(logFile, `[${currentTime}] Url request failed: ${task.url}, task id: ${task.id}\n`); } } //更新tasks,去掉已完成的 _self.tasks = _self.tasks.filter((item) => item.status != 'done'); } //自动查询监控任务结果 autoQueryTaskResult() { const _self = this; const frequence = typeof(this.config.resultQueryFrequence) != 'undefined' && this.config.resultQueryFrequence ? this.config.resultQueryFrequence : 5; //5 分钟检测一次 const cronjob = cron.schedule(`*/${frequence} * * * *`, async () => { if (_self.tasks.length == 0) { console.error("No tasks"); return false; } await _self.queryTasks(); }, { scheduled: false }); cronjob.start(); common.log('Cronjob of monit task result query started.'); } //初始化 async init() { await this.getConfig(); this.autoReloadConfigs(); this.autoCreateMonitTask(); this.autoQueryTaskResult(); } } export default Monitor;