nodejs PM2监控及报警邮件发送(二)

前言

用过nodejs都知道PM2,这章主要讲讲PM2监控程序及报警邮件
用pm2 启动app后,app挂掉自动拉起,但是维护人员不知道啊,所以需要其他方式通过(如邮件)

1:环境
centos7
node14

2: 安装nodejs 及 pm2
1: node安装 (以node-v14.17.3-linux-x64为例) 版本自行选择
1>下载 node-v14.17.3-linux-x64.tar.xz 网上自行去搜
路径: /home/node-v14.17.3-linux-x64.tar.xz
2>解压缩
xz -d node-v14.17.3-linux-x64.tar.xz
tar -xf node-v14.17.3-linux-x64.tar
3>创建软链接
ln -s /home/node-v14.17.3-linux-x64/bin/npm /usr/bin/npm
ln -s /home/node-v14.17.3-linux-x64/bin/node /usr/bin/node
4>测试
node -v

2: 安装pm2
1> npm install -g pm2 //全局安装
安装完 如下

[root@VM-22-234-centos nodejsserver0628]# npm install -g pm2
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
/home/node-v14.17.3-linux-x64/bin/pm2 -> /home/node-v14.17.3-linux-x64/lib/node_modules/pm2/bin/pm2
/home/node-v14.17.3-linux-x64/bin/pm2-dev -> /home/node-v14.17.3-linux-x64/lib/node_modules/pm2/bin/pm2-dev
/home/node-v14.17.3-linux-x64/bin/pm2-docker -> /home/node-v14.17.3-linux-x64/lib/node_modules/pm2/bin/pm2-docker
/home/node-v14.17.3-linux-x64/bin/pm2-runtime -> /home/node-v14.17.3-linux-x64/lib/node_modules/pm2/bin/pm2-runtime
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.3.2 (node_modules/pm2/node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: 

2> 创建软连接
ln -s /home/node-v14.17.3-linux-x64/bin/pm2 /usr/bin/pm2

3>pm2 命令

$ pm2 start app.js -i 4 #后台运行pm2,启动4个app.js 
                                # 也可以把'max' 参数传递给 start
                                # 正确的进程数目依赖于Cpu的核心数目
$ pm2 start app.js --name my-api # 命名进程
$ pm2 list               # 显示所有进程状态
$ pm2 monit              # 监视所有进程
$ pm2 logs               #  显示所有进程日志
$ pm2 stop all           # 停止所有进程
$ pm2 restart all        # 重启所有进程
$ pm2 reload all         # 0秒停机重载进程 (用于 NETWORKED 进程)
$ pm2 stop 0             # 停止指定的进程
$ pm2 restart 0          # 重启指定的进程
$ pm2 startup            # 产生 init 脚本 保持进程活着
$ pm2 web                # 运行健壮的 computer API endpoint (http://localhost:9615)
$ pm2 delete 0           # 杀死指定的进程
$ pm2 delete all         # 杀死全部进程

3:监控及邮件
monit_app.js 内容如下

const pm2 = require('pm2')
//const sendmail = require('./sendmail');
function pm2checkdump(){
  console.log("enter pm2checkdump");
  pm2.connect(function(err) {
  if (err) {
    console.error(err)
    //process.exit(2)
	return 
  }
  
  pm2.list((err, list) => {
    //  console.log(err, list)
	  if(err){
		  
	  }else{
		  parsedata(list);
	  }
	  pm2.disconnect()
  })

  })
}

const fs = require('fs')
const path = require('path')

var mapprocess = {};
map['key1'] = 1;
//map['key2@'] = 2;
 
//console.log(map['key1']);//结果是1.
console.log(map['key2@']);//结果是2.
var shellcount = 0 ;
var writelogcount = 0;
var monit_pid = 0 ;  //监控程序的PID
var waiwang_ip  = "" ; //外网IP
//如果遍历map
for(var prop in mapprocess){
    if(mapprocess.hasOwnProperty(prop)){
        console.log('key is ' + prop +' and value is' + mapprocess[prop]);
    }
}

var exec = require('child_process').exec;

function sendmailto(context){
	let sendermail =   "sendermail@163.com" ;    //发送人
	let receiver = "receiver1@qq.com,receiver2@qq.com"; //接收人
	let mailserver = "smtp.163.com:25" ;		//邮箱服务器及端口
	let mailpw = "shouquanma123"; //授权码
	
	let  cmdstr = "sendEmail -o tls=no -f " +sendermail + " -t " + receiver + "   -s " + mailserver + " -xu " + sendermail +" -xp "+ mailpw + "  -u " ;
	cmdstr = cmdstr + context ;
	cmdstr = cmdstr + " -m " +context ;
	
	
//	" '33邮件测试33' -m '33邮件正文你的错误了2'" ;
	
	exec(cmdstr ,function(error, stdout, stderr){
		if(error) {
			console.error('error: ' + error);
			return;
		}
		console.log('stdout: ' + stdout);
	});
}

//查询外网IP
function queryip(){
	//curl ifconfig.me   返回IP
	let cmdstr = "curl ip.cip.cc"; //
	//返回IP 加地区  curl cip.cc
	exec(cmdstr ,function(error, stdout, stderr){
		if(error) {
			console.error('error: ' + error);
			return;
		}
		//console.log('stdout: ' + stdout);
		waiwang_ip = ''+stdout ;
		console.log(waiwang_ip);
	});
}

//测试发送邮件
function testmail(){
	let curtime = Date.now();
	let text ="["+curtime+"] "+"testmail!!";
	sendmailto(text) ;
}


var http=require('http');
//http post
function  httppost(url,port,path,jsobject){
//	var data = {
//		a: 111,
//		time: Date.now()
//	}
    if (typeof(jsobject) != 'object')){
		return ;
	}
    port  = port || 80 ;
	path = path || '/'  ;
	
	var dataString = JSON.stringify(jsobject)	// 转换为字符串格式
	var option = {
		hostname: url,//'127.0.0.1',	// 要访问的服务器的ip地址
		port: port,//3000,  // 要访问的服务器的端口
		path: path,//'/xx/xx', // 请求的接口
		method: 'POST',	// 请求方式
		headers: {  
			'Content-Type':'application/json',
			'Content-Length':dataString.length
		} 
	}
	var rep = http.request(option, function(res){
		console.log('状态码:' + res.statusCode)
		console.log('响应头:' + JSON.stringify(res.headers))
		res.setEncoding('utf8');
		res.on('data', (chunk) => {
			//console.log(`响应主体: ${chunk}`);
		});
		res.on('end', () => {
			//console.log('响应中已无数据');
		});
	})

	req.on('error', (e) => {
		console.error(`请求遇到问题: ${e.message}`);
	});
	req.write(dataString)	// post请求携带的参数(将数据写入请求主体)
	req.end(); 	// 必须始终调用 req.end() 来表示请求的结束

}
	

function parsedata(data){
	try{
		// 异步写入数据到文件
		//fs.writeFile(file, JSON.stringify(data, null, 4), { encoding: 'utf8' }, err => {})
		let curtime = Date.now();
	//	let riqi = Date('Y-m-d H:i:s',''+curtime);
		let date = new Date(curtime);
		let dt = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()+' '+date.getHours()+':'+date.getMinutes()+':'+date.getSeconds()
		let ymr = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() ;
		let logfile = path.resolve(__dirname, "./log/"+ymr+"_restart.log");
		let tmpfile = path.resolve(__dirname, './log/pm2listlog.log')
	
		if(typeof(data) == 'object'){
			for (var i = 0; i < data.length; i++) {
				 let jsonobject = data[i] ;
				//console.log(dt,i, jsonobject.name,jsonobject.pm2_env.restart_time);  //jsonobject.pid
				if (mapprocess[jsonobject.name]){
					let curcount = mapprocess[jsonobject.name];
					if(jsonobject.pm2_env.restart_time >  curcount){
						console.log("restart",jsonobject.name,curcount)
						mapprocess[jsonobject.name] =  jsonobject.pm2_env.restart_time
						
						let text =''+waiwang_ip+"["+curtime+"] "+jsonobject.name+" restart!";
						sendmailto(text) ;
						
						fs.writeFile(logfile, text, { encoding: 'utf8', flag: 'a'}, err => {})
						
					}else{
						console.log(dt,jsonobject.name,curcount,jsonobject.pm2_env.restart_time)
					}
				}else {
					//if(shellcount > 0   || jsonobject.name.indexOf("monit") < 0) {
					mapprocess[jsonobject.name] = jsonobject.pm2_env.restart_time ;
					//	console.log("first save[0]",jsonobject.name,jsonobject.pm2_env.restart_time);
					//}
					console.log("first save",jsonobject.name,jsonobject.pm2_env.restart_time);
				}
			}
			
//			let newdata = JSON.stringify(data, null, 4);
			if((shellcount%16) == 0){
				let newdata = JSON.stringify(data, null, 4);
				newdata = ''+dt+' '+newdata  ; //增加时间
				if(writelogcount < 24){
					fs.writeFile(tmpfile, newdata, { encoding: 'utf8', flag: 'a' }, err => {})  //追加
				}else{
					fs.writeFile(tmpfile, newdata, { encoding: 'utf8', flag: 'w' }, err => {})   //截断
					writelogcount  = 0 ;
				}
				writelogcount+=1 ;
			}
			
			shellcount += 1; 
		}
		/// var json = JSON.parse(data);
		
		 
	}catch(e){
		console.log(e)
	}
}

const timeval = 120*1000  ;// 120秒
setInterval(pm2checkdump, timeval); //启动定时器 //多少时间后再启动
console.log("setInterval setup"+timeval);
pm2checkdump(); 	//所以这里先启动一次
queryip() ;			//查询外网IP
//testmail();

原理
通过 pm2checkdump 解析数据,记录每个app的次数,
通过对比重启次数 判定该app是否被拉起过
启动监控 pm2 start ./monit_app.js //(根据文件路径自行修改)

在这里插入图片描述
4: 注意 把发送人邮箱 放入白名单里,以免收不到邮件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值