mm_monitor 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/example/index.js +48 -0
- package/index.js +16 -143
- package/lib/monitor.js +146 -0
- package/package.json +40 -33
- package/test.js +32 -13
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# mm_monitor
|
|
2
|
+
|
|
3
|
+
mm_monitor 是一个网站运行状态监听告警模块,按固定心跳间隔轮询检测目标 URL 是否可正常访问(HTTP 200),检测到异常时自动通过短信(短信宝接口)与邮件通知运维人员,并支持异常后的冷却重跑,避免连续重复告警。适合对线上服务做轻量级存活监控。
|
|
4
|
+
|
|
5
|
+
## 项目信息
|
|
6
|
+
|
|
7
|
+
- **当前版本**: 1.0.6
|
|
8
|
+
- **更新日期**: 2026-10-04
|
|
9
|
+
- **Gitee地址**: https://gitee.com/qiuwenwu91/mm_monitor
|
|
10
|
+
- **依赖**:
|
|
11
|
+
- mm_https ^1.6.7(HTTP 客户端,用于探活请求)
|
|
12
|
+
- mm_phone ^1.0.2(短信发送,采用短信宝 API 接口)
|
|
13
|
+
- mm_email ^1.0.8(邮件发送)
|
|
14
|
+
|
|
15
|
+
## 特点
|
|
16
|
+
|
|
17
|
+
- 心跳轮询检测多个监听项,间隔可配置(默认 30 秒)。
|
|
18
|
+
- 探活失败后间隔 1 秒自动复检一次,两次均失败才告警,减少误报。
|
|
19
|
+
- 同一轮异常只告警一次(内部 `sended` 标志去重)。
|
|
20
|
+
- 告警后停止轮询,进入冷却期(默认 3600 秒)后自动重新运行,避免连续通知轰炸。
|
|
21
|
+
- 短信 + 邮件双通道通知,各通道可通过 `state` 开关独立启用。
|
|
22
|
+
- 单项检测异常被 try/catch 捕获并记录日志,不影响其余监听项。
|
|
23
|
+
|
|
24
|
+
## 安装
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install mm_monitor
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 基本使用
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
const Monitor = require('mm_monitor');
|
|
34
|
+
|
|
35
|
+
const monitor = new Monitor({
|
|
36
|
+
phone: { // 短信通道(短信宝)
|
|
37
|
+
state: 1, // 是否启用
|
|
38
|
+
username: 'your-sms-user',
|
|
39
|
+
password: 'your-sms-password'
|
|
40
|
+
},
|
|
41
|
+
email: { // 邮件通道
|
|
42
|
+
state: 1,
|
|
43
|
+
host: 'smtp.qq.com',
|
|
44
|
+
username: 'ops@qq.com',
|
|
45
|
+
password: 'your-smtp-authcode'
|
|
46
|
+
},
|
|
47
|
+
listen: [
|
|
48
|
+
{
|
|
49
|
+
name: 'AI考勤系统', // 网站名称
|
|
50
|
+
url: 'https://example.com/api/health', // 探活地址
|
|
51
|
+
email: 'ops@qq.com', // 告警邮箱
|
|
52
|
+
phone: '13800000000', // 告警手机号
|
|
53
|
+
content: '【考勤系统】服务器异常,请尽快进行维护!' // 告警内容
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
interval: 30, // 心跳间隔(秒)
|
|
57
|
+
interval_again: 3600 // 告警后冷却时长(秒)
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
monitor.run(); // 启动监听
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API 说明
|
|
64
|
+
|
|
65
|
+
导出唯一类 `Monitor`。
|
|
66
|
+
|
|
67
|
+
### 构造函数
|
|
68
|
+
|
|
69
|
+
`new Monitor(config)` — `config` 会与内置默认配置合并(`Object.assign`),并自动调用 `init` 初始化短信、邮件通道实例。
|
|
70
|
+
|
|
71
|
+
| 配置项 | 类型 | 默认值 | 说明 |
|
|
72
|
+
| --- | --- | --- | --- |
|
|
73
|
+
| phone | `Object` | `{ state: 1, username: '', password: '' }` | 短信通道配置,传给 `mm_phone`(短信宝接口);`state` 为是否启用 |
|
|
74
|
+
| email | `Object` | `{ state: 1, host: 'smtp.qq.com', username: '', password: '' }` | 邮件通道配置,传给 `mm_email`;`password` 一般为 SMTP 授权码 |
|
|
75
|
+
| listen | `Array` | `[]` | 监听项列表,每项含 `name`(网站名称)、`url`(探活地址)、`email`(告警邮箱)、`phone`(告警手机号)、`content`(告警内容) |
|
|
76
|
+
| interval | `Number` | `30` | 心跳轮询间隔,单位秒 |
|
|
77
|
+
| interval_again | `Number` | `3600` | 出现异常并告警后的冷却时长,单位秒,到期后自动重新 `run` |
|
|
78
|
+
|
|
79
|
+
### 实例方法
|
|
80
|
+
|
|
81
|
+
| 方法 | 签名 | 返回值 | 说明 |
|
|
82
|
+
| --- | --- | --- | --- |
|
|
83
|
+
| init | `await init(config)` | `Promise` | 合并配置到 `this.config`,创建 `mm_phone` 短信实例与 `mm_email` 邮件实例。构造函数已自动调用 |
|
|
84
|
+
| checkServer | `await checkServer(url)` | `Boolean` | 用 `mm_https` GET 请求 `url`,响应状态码为 200 返回 `true`,否则 `false` |
|
|
85
|
+
| notiy | `await notiy(o)` | `Promise` | 发送告警(方法名拼写以源码为准)。解构 `o` 的 `phone`、`email`、`title`、`content`:先 `sms.send(phone, content)`,再 `email.send(title || '服务器异常', content, null, email)` |
|
|
86
|
+
| loop | `await loop()` | `Promise` | 执行一轮巡检:逐项 `checkServer`,失败则 1 秒后复检;仍未恢复且本轮未告警过则调用 `notiy`。若本轮发生告警,停止定时器并在 `interval_again` 秒后重新 `run` |
|
|
87
|
+
| run | `await run()` | `Promise` | 重置告警标志,按 `interval` 秒周期启动 `setInterval` 循环执行 `loop` |
|
|
88
|
+
|
|
89
|
+
> 注意:运行依赖全局工具对象 `$`(`$.log` 日志、`$.sleep` 延时),需在已加载相应基础库的环境中使用。
|
|
90
|
+
|
|
91
|
+
## 使用示例
|
|
92
|
+
|
|
93
|
+
### 场景一:从配置文件启动监听
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
const Monitor = require('mm_monitor');
|
|
97
|
+
|
|
98
|
+
const config = './config.json'.loadJson(); // 含 phone/email/listen/interval 等
|
|
99
|
+
const monitor = new Monitor(config);
|
|
100
|
+
monitor.run();
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 场景二:监听多个站点
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
const monitor = new Monitor({
|
|
107
|
+
phone: { state: 1, username: 'sms-user', password: 'sms-pass' },
|
|
108
|
+
email: { state: 1, host: 'smtp.qq.com', username: 'ops@qq.com', password: 'authcode' },
|
|
109
|
+
listen: [
|
|
110
|
+
{ name: '官网', url: 'https://www.example.com', email: 'ops@qq.com', phone: '13800000000', content: '【官网】服务器异常,请尽快维护!' },
|
|
111
|
+
{ name: 'API服务', url: 'https://api.example.com/health', email: 'ops@qq.com', phone: '13800000000', content: '【API】服务不可用,请尽快维护!' }
|
|
112
|
+
],
|
|
113
|
+
interval: 60
|
|
114
|
+
});
|
|
115
|
+
monitor.run();
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 场景三:仅手动单次探活(不启动定时器)
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
const Monitor = require('mm_monitor');
|
|
122
|
+
|
|
123
|
+
const monitor = new Monitor({});
|
|
124
|
+
(async () => {
|
|
125
|
+
const ok = await monitor.checkServer('https://www.example.com');
|
|
126
|
+
console.log(ok ? '服务正常' : '服务异常');
|
|
127
|
+
})();
|
|
128
|
+
```
|
package/example/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mm_monitor 最小可运行示例
|
|
3
|
+
* @description 演示 Monitor 类的实例化、工厂获取实例与核心方法存在性。
|
|
4
|
+
* 注意:不会真正发起网站检测与短信/邮件通知;phone/email 配置为示例假值,实际使用时请替换为真实配置。
|
|
5
|
+
*/
|
|
6
|
+
const { Monitor, monitorAdmin } = require('../index.js');
|
|
7
|
+
|
|
8
|
+
/** 示例假配置(实际使用时替换为真实的手机号/邮箱通知配置) */
|
|
9
|
+
const CONFIG = {
|
|
10
|
+
phone: {
|
|
11
|
+
state: 0,
|
|
12
|
+
username: 'example_user',
|
|
13
|
+
password: 'example_password'
|
|
14
|
+
},
|
|
15
|
+
email: {
|
|
16
|
+
state: 0,
|
|
17
|
+
host: 'smtp.qq.com',
|
|
18
|
+
username: 'example@qq.com',
|
|
19
|
+
password: 'example_code'
|
|
20
|
+
},
|
|
21
|
+
listen: [],
|
|
22
|
+
interval: 60
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 主函数
|
|
27
|
+
*/
|
|
28
|
+
function main() {
|
|
29
|
+
console.log('== mm_monitor 示例开始 ==');
|
|
30
|
+
|
|
31
|
+
// 实例化(仅初始化配置与通知器,不启动监听)
|
|
32
|
+
const monitor = new Monitor(CONFIG);
|
|
33
|
+
console.log('实例化 Monitor 成功');
|
|
34
|
+
console.log('监听列表:', Array.isArray(monitor.config.listen) ? monitor.config.listen.length + ' 项' : '无效');
|
|
35
|
+
|
|
36
|
+
// 通过工厂函数获取按作用域缓存的实例
|
|
37
|
+
const inst = monitorAdmin('example', { listen: [] });
|
|
38
|
+
console.log('monitorAdmin 获取实例:', inst instanceof Monitor);
|
|
39
|
+
|
|
40
|
+
// 核心方法存在性检查(不真正执行,避免联网检测与发送通知)
|
|
41
|
+
const METHODS = ['init', 'checkServer', 'notiy', 'loop', 'run'];
|
|
42
|
+
const missing = METHODS.filter((name) => typeof inst[name] !== 'function');
|
|
43
|
+
console.log('核心方法检查:', missing.length === 0 ? '全部存在' : '缺失: ' + missing.join(','));
|
|
44
|
+
|
|
45
|
+
console.log('== mm_monitor 示例结束 ==');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
main();
|
package/index.js
CHANGED
|
@@ -1,143 +1,16 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
state: 1,
|
|
18
|
-
// 用户名
|
|
19
|
-
username: '',
|
|
20
|
-
// 密码,一般为授权码
|
|
21
|
-
password: ''
|
|
22
|
-
},
|
|
23
|
-
email: {
|
|
24
|
-
// 是否启用
|
|
25
|
-
state: 1,
|
|
26
|
-
// 服务器地址
|
|
27
|
-
host: 'smtp.qq.com',
|
|
28
|
-
// 用户名
|
|
29
|
-
username: 'xxxxxx@qq.com',
|
|
30
|
-
// 密码,一般为授权码
|
|
31
|
-
password: ''
|
|
32
|
-
},
|
|
33
|
-
listen: [
|
|
34
|
-
// {
|
|
35
|
-
// // 网站名称
|
|
36
|
-
// name: "AI考勤系统",
|
|
37
|
-
// // URL地址
|
|
38
|
-
// url: "https://xxx.xxx.com/xxx/xxx/xxx",
|
|
39
|
-
// // 推送到邮箱
|
|
40
|
-
// email: "xxx@qq.com",
|
|
41
|
-
// // 发送短信到
|
|
42
|
-
// phone: "xxx",
|
|
43
|
-
// // 推送的内容
|
|
44
|
-
// content: "【xxx】服务器异常,请尽快进行维护!--xxx系统"
|
|
45
|
-
// }
|
|
46
|
-
],
|
|
47
|
-
// 心跳间隔时长
|
|
48
|
-
interval: 30,
|
|
49
|
-
interval_again: 3600
|
|
50
|
-
}
|
|
51
|
-
// 是否已发送,用于避免重复发送
|
|
52
|
-
this.sended = false;
|
|
53
|
-
this.init(config);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 初始化
|
|
59
|
-
* @param {Object} config 配置
|
|
60
|
-
*/
|
|
61
|
-
Monitor.prototype.init = async function(config) {
|
|
62
|
-
Object.assign(this.config, config);
|
|
63
|
-
this.sms = new SMS(this.config.phone);
|
|
64
|
-
this.email = new Email(this.config.email);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 检测访问是否正常
|
|
69
|
-
* @param {String} url 服务器地址
|
|
70
|
-
*/
|
|
71
|
-
Monitor.prototype.checkServer = async function(url) {
|
|
72
|
-
var http = new Http();
|
|
73
|
-
var res = await http.get(url);
|
|
74
|
-
if (res.status == 200) {
|
|
75
|
-
return true;
|
|
76
|
-
} else {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* 通知
|
|
83
|
-
* @param {Object} o 通知的对象信息
|
|
84
|
-
*/
|
|
85
|
-
Monitor.prototype.notiy = async function(o) {
|
|
86
|
-
var {
|
|
87
|
-
phone,
|
|
88
|
-
email,
|
|
89
|
-
title,
|
|
90
|
-
content
|
|
91
|
-
} = o;
|
|
92
|
-
await this.sms.send(phone, content);
|
|
93
|
-
await this.email.send(title || "服务器异常", content, null, email);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* 循环检测
|
|
98
|
-
*/
|
|
99
|
-
Monitor.prototype.loop = async function() {
|
|
100
|
-
var lt = this.config.listen;
|
|
101
|
-
var hasBug = false;
|
|
102
|
-
for (var i = 0; i < lt.length; i++) {
|
|
103
|
-
var o = lt[i];
|
|
104
|
-
try {
|
|
105
|
-
var bl = await this.checkServer(o.url);
|
|
106
|
-
if (!bl) {
|
|
107
|
-
$.sleep(1000);
|
|
108
|
-
bl = await this.checkServer(o.url);
|
|
109
|
-
if (!bl) {
|
|
110
|
-
console.log("发生异常", (new Date()).toStr('yyyy-MM-dd hh:mm:ss'), o);
|
|
111
|
-
if (!this.sended) {
|
|
112
|
-
this.sended = true;
|
|
113
|
-
await this.notiy(o);
|
|
114
|
-
hasBug = true;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
} catch (err) {
|
|
119
|
-
console.error(err);
|
|
120
|
-
}
|
|
121
|
-
$.sleep(1000);
|
|
122
|
-
}
|
|
123
|
-
if (hasBug) {
|
|
124
|
-
// 如果出现异常,则先暂停运行
|
|
125
|
-
clearInterval(this.timer);
|
|
126
|
-
// 等过了N久后再运行,避免连续通知
|
|
127
|
-
setTimeout(async () => {
|
|
128
|
-
await this.run();
|
|
129
|
-
}, this.config.interval_again * 1000);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* 运行监听
|
|
135
|
-
*/
|
|
136
|
-
Monitor.prototype.run = async function() {
|
|
137
|
-
this.sended = false;
|
|
138
|
-
this.timer = setInterval(async () => {
|
|
139
|
-
await this.loop();
|
|
140
|
-
}, this.config.interval * 1000);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
module.exports = Monitor;
|
|
1
|
+
const Monitor = require('./lib/monitor');
|
|
2
|
+
const Admin = require('mm_corejs').Admin;
|
|
3
|
+
|
|
4
|
+
const admin = new Admin();
|
|
5
|
+
admin.setClass(Monitor);
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
Monitor,
|
|
9
|
+
admin,
|
|
10
|
+
monitorAdmin(scope, config = {}) {
|
|
11
|
+
if (!scope) {
|
|
12
|
+
scope = 'os';
|
|
13
|
+
}
|
|
14
|
+
return admin.get(scope, config);
|
|
15
|
+
}
|
|
16
|
+
};
|
package/lib/monitor.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
const Http = require('mm_https');
|
|
2
|
+
const { sleep, date } = require('mm_helper');
|
|
3
|
+
const SMS = require('mm_phone').Phone;
|
|
4
|
+
const Email = require('mm_email').Mail;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 短信通知类: 采用短信宝的API接口
|
|
8
|
+
*/
|
|
9
|
+
class Monitor {
|
|
10
|
+
/**
|
|
11
|
+
* 构造函数
|
|
12
|
+
* @param {Object} config 配置参数
|
|
13
|
+
*/
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = {
|
|
16
|
+
phone: {
|
|
17
|
+
// 是否启用
|
|
18
|
+
state: 1,
|
|
19
|
+
// 用户名
|
|
20
|
+
username: '',
|
|
21
|
+
// 密码,一般为授权码
|
|
22
|
+
password: ''
|
|
23
|
+
},
|
|
24
|
+
email: {
|
|
25
|
+
// 是否启用
|
|
26
|
+
state: 1,
|
|
27
|
+
// 服务器地址
|
|
28
|
+
host: 'smtp.qq.com',
|
|
29
|
+
// 用户名
|
|
30
|
+
username: 'xxxxxx@qq.com',
|
|
31
|
+
// 密码,一般为授权码
|
|
32
|
+
password: ''
|
|
33
|
+
},
|
|
34
|
+
listen: [
|
|
35
|
+
// {
|
|
36
|
+
// // 网站名称
|
|
37
|
+
// name: "AI考勤系统",
|
|
38
|
+
// // URL地址
|
|
39
|
+
// url: "https://xxx.xxx.com/xxx/xxx/xxx",
|
|
40
|
+
// // 推送到邮箱
|
|
41
|
+
// email: "xxx@qq.com",
|
|
42
|
+
// // 发送短信到
|
|
43
|
+
// phone: "xxx",
|
|
44
|
+
// // 推送的内容
|
|
45
|
+
// content: "【xxx】服务器异常,请尽快进行维护!--xxx系统"
|
|
46
|
+
// }
|
|
47
|
+
],
|
|
48
|
+
// 心跳间隔时长
|
|
49
|
+
interval: 30,
|
|
50
|
+
interval_again: 3600
|
|
51
|
+
}
|
|
52
|
+
// 是否已发送,用于避免重复发送
|
|
53
|
+
this.sended = false;
|
|
54
|
+
// 日志记录器(可经 config.logger 注入,缺省使用 console)
|
|
55
|
+
this._logger = config && config.logger ? config.logger : console;
|
|
56
|
+
this.init(config);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 初始化
|
|
62
|
+
* @param {Object} config 配置
|
|
63
|
+
*/
|
|
64
|
+
Monitor.prototype.init = async function(config) {
|
|
65
|
+
Object.assign(this.config, config);
|
|
66
|
+
this.sms = new SMS(this.config.phone);
|
|
67
|
+
this.email = new Email(this.config.email);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 检测访问是否正常
|
|
72
|
+
* @param {String} url 服务器地址
|
|
73
|
+
*/
|
|
74
|
+
Monitor.prototype.checkServer = async function(url) {
|
|
75
|
+
var http = new Http();
|
|
76
|
+
var res = await http.get(url);
|
|
77
|
+
if (res.status == 200) {
|
|
78
|
+
return true;
|
|
79
|
+
} else {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 通知
|
|
86
|
+
* @param {Object} o 通知的对象信息
|
|
87
|
+
*/
|
|
88
|
+
Monitor.prototype.notiy = async function(o) {
|
|
89
|
+
var {
|
|
90
|
+
phone,
|
|
91
|
+
email,
|
|
92
|
+
title,
|
|
93
|
+
content
|
|
94
|
+
} = o;
|
|
95
|
+
await this.sms.send(phone, content);
|
|
96
|
+
await this.email.send(title || "服务器异常", content, null, email);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 循环检测
|
|
101
|
+
*/
|
|
102
|
+
Monitor.prototype.loop = async function() {
|
|
103
|
+
var lt = this.config.listen;
|
|
104
|
+
var hasBug = false;
|
|
105
|
+
for (var i = 0; i < lt.length; i++) {
|
|
106
|
+
var o = lt[i];
|
|
107
|
+
try {
|
|
108
|
+
var bl = await this.checkServer(o.url);
|
|
109
|
+
if (!bl) {
|
|
110
|
+
await sleep(1000);
|
|
111
|
+
bl = await this.checkServer(o.url);
|
|
112
|
+
if (!bl) {
|
|
113
|
+
this._logger.debug("发生异常", date.toStr(new Date(), 'yyyy-MM-dd hh:mm:ss'), o);
|
|
114
|
+
if (!this.sended) {
|
|
115
|
+
this.sended = true;
|
|
116
|
+
await this.notiy(o);
|
|
117
|
+
hasBug = true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} catch (err) {
|
|
122
|
+
this._logger.error(err);
|
|
123
|
+
}
|
|
124
|
+
await sleep(1000);
|
|
125
|
+
}
|
|
126
|
+
if (hasBug) {
|
|
127
|
+
// 如果出现异常,则先暂停运行
|
|
128
|
+
clearInterval(this.timer);
|
|
129
|
+
// 等过了N久后再运行,避免连续通知
|
|
130
|
+
setTimeout(async () => {
|
|
131
|
+
await this.run();
|
|
132
|
+
}, this.config.interval_again * 1000);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 运行监听
|
|
138
|
+
*/
|
|
139
|
+
Monitor.prototype.run = async function() {
|
|
140
|
+
this.sended = false;
|
|
141
|
+
this.timer = setInterval(async () => {
|
|
142
|
+
await this.loop();
|
|
143
|
+
}, this.config.interval * 1000);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = Monitor;
|
package/package.json
CHANGED
|
@@ -1,33 +1,40 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mm_monitor",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "超级美眉监听器,用于监听网站运行是否异常并给运维人员发短信、邮箱通知",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "node test.js"
|
|
8
|
-
},
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://gitee.com/qiuwenwu91/mm_monitor.git"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "mm_monitor",
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "超级美眉监听器,用于监听网站运行是否异常并给运维人员发短信、邮箱通知",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node test.js"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://gitee.com/qiuwenwu91/mm_monitor.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mm_mod",
|
|
15
|
+
"mm_crosscut",
|
|
16
|
+
"mm_alerting",
|
|
17
|
+
"mvc",
|
|
18
|
+
"web",
|
|
19
|
+
"view",
|
|
20
|
+
"model",
|
|
21
|
+
"controller",
|
|
22
|
+
"render",
|
|
23
|
+
"template"
|
|
24
|
+
],
|
|
25
|
+
"layer": "crosscut",
|
|
26
|
+
"group": "alerting",
|
|
27
|
+
"author": "邱文武",
|
|
28
|
+
"license": "ISC",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://gitee.com/qiuwenwu91/mm_monitor/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://gitee.com/qiuwenwu91/mm_monitor#readme",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"mm_corejs": "^1.1.4",
|
|
35
|
+
"mm_email": "^1.1.0",
|
|
36
|
+
"mm_helper": "^1.0.3",
|
|
37
|
+
"mm_https": "^1.7.1",
|
|
38
|
+
"mm_phone": "^1.0.2"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/test.js
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
const assert = require('assert');
|
|
3
|
+
const mod = require('./index.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 运行 mm_monitor 模块测试
|
|
7
|
+
* 仅验证导出结构与实例化,不调用 run() 以避免真实联网与发送通知
|
|
8
|
+
* @returns {Promise<void>}
|
|
9
|
+
*/
|
|
10
|
+
async function runTest() {
|
|
11
|
+
// 验证导出结构
|
|
12
|
+
assert.strictEqual(typeof mod.Monitor, 'function', '应导出 Monitor');
|
|
13
|
+
assert.ok(mod.admin, '应导出 admin');
|
|
14
|
+
assert.strictEqual(typeof mod.monitorAdmin, 'function', '应导出 monitorAdmin 函数');
|
|
15
|
+
|
|
16
|
+
// 实例化 Monitor(不调用 run,避免真实请求)
|
|
17
|
+
const monitor = new mod.Monitor({ listen: [], interval: 60 });
|
|
18
|
+
assert.ok(monitor instanceof mod.Monitor, 'Monitor 应可实例化');
|
|
19
|
+
assert.ok(monitor.config, '实例应包含 config');
|
|
20
|
+
assert.ok(Array.isArray(monitor.config.listen), 'config 应包含 listen 数组');
|
|
21
|
+
|
|
22
|
+
// 验证 admin 工厂获取实例
|
|
23
|
+
const inst = mod.monitorAdmin('test_scope', { listen: [] });
|
|
24
|
+
assert.ok(inst instanceof mod.Monitor, 'monitorAdmin 返回的实例应为 Monitor 类型');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
runTest().then(() => {
|
|
28
|
+
console.log('mm_monitor 模块测试通过');
|
|
29
|
+
}).catch((err) => {
|
|
30
|
+
console.error(err);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
});
|