| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- /// 磁盘空间监控
- const { exec } = require('child_process');
- const { promisify } = require('util');
- const execAsync = promisify(exec);
- const { sendEmail } = require('./email');
- const { sendSms } = require('./sms');
- const SmsTemplate = require('./sms-templates');
- // 阈值配置
- const USAGE_THRESHOLD = 90; // 使用率阈值 90%
- const FREE_SPACE_THRESHOLD = 10; // 剩余空间阈值 10G
- async function getDiskInfo() {
- try {
- const { stdout } = await execAsync('df -h /');
- const lines = stdout.trim().split('\n');
-
- if (lines.length < 2) {
- throw new Error('无法解析df命令输出');
- }
- // 解析df输出
- const dataLine = lines[1].trim().split(/\s+/);
- const [filesystem, size, used, avail, usePercent, mountpoint] = dataLine;
-
- return {
- filesystem,
- size,
- used,
- avail,
- usePercent: parseInt(usePercent),
- mountpoint,
- raw: stdout
- };
- } catch (error) {
- throw new Error(`获取磁盘信息失败: ${error.message}`);
- }
- }
- function parseSize(sizeStr) {
- // 将 "106G", "1.5T" 等格式转换为GB数值
- const match = sizeStr.match(/^([\d.]+)([KMGT]?)$/i);
- if (!match) return 0;
-
- const value = parseFloat(match[1]);
- const unit = match[2].toUpperCase();
-
- const multipliers = { '': 1/1024, 'K': 1/1024/1024, 'M': 1/1024, 'G': 1, 'T': 1024 };
- return value * (multipliers[unit] || 1);
- }
- async function checkDiskSpace() {
- let diskInfo;
-
- try {
- diskInfo = await getDiskInfo();
- } catch (e) {
- console.error('磁盘信息获取失败:', e.message);
- return {
- result: false,
- errcode: 200,
- title: '磁盘监控:无法获取磁盘信息',
- sms: SmsTemplate.SMS_DISK_ERROR,
- data: [e.message],
- diskInfo: null
- };
- }
- const usagePercent = diskInfo.usePercent;
- const availGB = parseSize(diskInfo.avail);
-
- console.log(`磁盘使用率: ${usagePercent}%, 剩余空间: ${availGB.toFixed(2)}GB`);
- // 检查是否超过阈值
- if (usagePercent >= USAGE_THRESHOLD || availGB < FREE_SPACE_THRESHOLD) {
- const reasons = [];
- if (usagePercent >= USAGE_THRESHOLD) {
- reasons.push(`使用率达到 ${usagePercent}% (阈值: ${USAGE_THRESHOLD}%)`);
- }
- if (availGB < FREE_SPACE_THRESHOLD) {
- reasons.push(`剩余空间仅 ${availGB.toFixed(2)}GB (阈值: ${FREE_SPACE_THRESHOLD}GB)`);
- }
- return {
- result: false,
- errcode: 201,
- title: '磁盘空间告警',
- sms: SmsTemplate.SMS_DISK_WARNING,
- data: [
- `文件系统: ${diskInfo.filesystem}`,
- `挂载点: ${diskInfo.mountpoint}`,
- `总容量: ${diskInfo.size}`,
- `已使用: ${diskInfo.used}`,
- `可用空间: ${diskInfo.avail}`,
- `使用率: ${usagePercent}%`,
- '',
- '告警原因:',
- ...reasons,
- '',
- '详细信息:',
- diskInfo.raw
- ],
- diskInfo
- };
- }
- return {
- result: true,
- errcode: 0,
- title: '磁盘空间正常',
- sms: SmsTemplate.SMS_RESUME,
- data: [
- `文件系统: ${diskInfo.filesystem}`,
- `使用率: ${usagePercent}%`,
- `剩余空间: ${diskInfo.avail}`
- ],
- diskInfo
- };
- }
- async function run(lastErrCode = 0) {
- console.log("检查磁盘空间...", new Date());
-
- try {
- let result = null;
-
- // 连续检测3次才发送通知,减少误报
- for (let i = 0; i < 3; i++) {
- result = await checkDiskSpace();
- console.log(result);
-
- if (!result.result) {
- console.warn("磁盘空间检查出现异常,一分钟后重试");
- await delay(60 * 1000);
- } else {
- console.log("磁盘空间正常");
- break;
- }
- }
- if (!result.result) {
- console.error("连续3次检查磁盘空间异常,发送通知");
- sendEmail(result.title, result.data);
- sendSms(result.sms);
- console.log("5分钟后再试");
- setTimeout(run, 5 * 60 * 1000, result.errcode);
- return;
- } else {
- // 如果上次是出错的情况,那么属于服务恢复,发送恢复通知
- if (lastErrCode === 200 || lastErrCode === 201) {
- sendEmail(result.title, result.data);
- sendSms(result.sms);
- }
- }
- } catch (err) {
- console.error(err.stack);
- }
- }
- function delay(ms) {
- return new Promise(done => setTimeout(done, ms));
- }
- module.exports = { run, checkDiskSpace };
- if (require.main == module) {
- run();
- }
|