Ubuntu 18.04
内核:55.0.0.36-generic
apt-get install monit
该程序会开机自动运行。
该程序帮助文档:
https://mmonit.com/monit/documentation/monit.html
vim /etc/monit/monitrc
第19行左右:
set daemon 120
这里默认是120s,表示每120秒检查一下被监视的程序状态。可以改小一点。例如,改成6啥的。
启用web服务,在第159行左右:
set httpd port 2812
use address localhost
allow localhost
allow admin:monit
至少去掉上面四行注释。这样,启动服务后,它会自动在后台运行http服务,显示各程序状态。这里是默认配置,即在浏览器打开 localhost:2812
就可以访问,而登录时,账号是admin
,密码是monit
。
每次修改完配置文件后,若要新配置生效,必须重启monit服务。
重启命令:systemctl restart monit
停止命令:systemctl stop monit
启动命令:systemctl start monit
查看当前服务状态:systemctl status monit
如果启动后,报错,提示不能启动,往往是配置文件写错了。使用查看当前服务状态命令,可以看到是哪里写错了。
注意:此服务会开机自启动。
关闭开机自启动:systemctl disable monit
开启开机自启动:systemctl enable monit
注:当程序正在后台运行时,关闭开机自启动操作,并不会关闭在后台运行的那个进程。
默认日志存放位置为/var/log/monit.log,此位置似乎可在上述配置文件中配置。
此处为示例。
需求:有一个待监视的程序,需要保证它一直在执行,不论是正常退出,还是出现segmentation fault 等情况导致退出,需要将其重启。
思路:写一个脚本,检查程序是否还在,不在就启动它。然后利用monit定时执行的功能,定时调用这个脚本进行检查即可。
该示例程序如下:
程序名 Watched.cpp
#include <iostream>
#include <thread>
using namespace std;
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
void raiseSegmentationFault(void)
{
cout << "Segmentation Fault Exit." << endl;
int *p = 0; // emtpy pointer.
*p = 0;
}
int main()
{
cout << "Start Watched..." << endl;
srand(time(NULL));
int a = rand();
bool raiseFlag = a % 2 == 0;
if (raiseFlag)
{
cout << "It will raise a segmentation fault after sleep." << endl;
}
else
{
cout << "It will normal exit after sleep." << endl;
}
int t = 10;
while (t--)
{
cout << "Sleep " << t << "s" << endl;
sleep(t);
}
if (raiseFlag)
{
// raise segment fault by random.
raiseSegmentationFault();
}
cout << "Normal Exit." << endl;
return 0;
}
该程序说明:此程序大约会在45秒后自动退出。但通过随机数控制,退出时状态有两种,每次退出时,各有一半概率选中,一种是正常执行完毕而退出,另一种是segmentation fault(通过操作空指针引发的异常)退出。
现在需要此程序需要一直在运行,不论是正常退出,还是segmentation fault 引起的退出,都应该将其再次启动。
使用g++正常编译此程序即可,例如 g++ Watched.cpp -o Watched.out。
假设编译后文件名为Watched.out
文件存放路径为:/home/hehe/Desktop/project/Watched/
/home/hehe/Desktop/project/Watched/ 目录结构如下:
该脚本即是检查程序是否还在,不在就启动它。
该脚本如下:
脚本名 check.sh
#! /bin/bash
Check_String="Watched.out"
Exclude_String="check.sh"
Restart_Command="/bin/bash /home/hehe/Desktop/project/Watched/start.sh"
PROCESS=$(ps -ajx | grep $Check_String | grep -v grep | grep -v $Exclude_String)
# echo $PROCESS
if [ -n "$PROCESS" ];
then
echo "Still Runing..."
else
echo "Try Restart..."
$Restart_Command
fi;
该脚本说明,利用ps命令查询进程,并通过grep命令查询指定字串代表的Watched.out程序是否存在。如果存在,则不进行操作。如果不存在,认为Watched.out程序已退出,则进行启动操作,请注意,脚本有超时执行时间,因此,检查完后,脚本必须退出。
记得使用 chmod +x check.sh 加执行权限。
文件存放路径为:/home/hehe/Desktop/project/Watched/
/home/hehe/Desktop/project/Watched/ 目录结构如下:
注:monit 是有root权限的,似乎该脚本及其启动的程序也会获得权限。
在check.sh中,如果没有查到程序在启动,则需要启动它,此处是通过执行start.sh脚本使其启动,请注意,脚本启动程序后,该脚本必须退出,否则会导致check.sh无法退出。
该脚本名:start.sh
#! /bin/bash -x
export DISPLAY=:0.0
cd /home/hehe/Desktop/project/Watched
#sudo gnome-terminal -- bash -c "./Watched.out;exec bash;"
sudo gnome-terminal -- bash -c "./Watched.out;"
该脚本说明,首先进入到相应的目录,然后新建一个终端,在终端中执行命令“./Watched.out;”,该脚本在新建终端后会自动退出,而终端会一直存在,直到Watched.out退出后退出,但如果后面加上“exec bash;”,则这个新终端在Watched.out退出后不会自动退出。
记得使用 chmod +x start.sh 加执行权限。
文件存放路径为:/home/hehe/Desktop/project/Watched/
/home/hehe/Desktop/project/Watched/ 目录结构如下:
vim /etc/monit/monitrc
参照第299行左右的写法,在文件中,加入如下两行语句。
check program Watched with path /home/hehe/Desktop/project/Watched/check.sh timeout 5 seconds
if status != 0 then alert
配置说明:
program Watched,这个Watched是表示名字,在不冲突的情况,可以任意起名。后续在web页面上,看到的就是这个名字。
path /home/hehe/Desktop/project/Watched/check.sh 这个路径即是每次要执行的文件。
timeout 5 seconds,如果check.sh执行了5s还没有执行完,则强行中断check.sh。注意,这个时间不能配置为负数。如果配置为0了,那就基本等于每次检查时都要中断它了。
if status != 0 then alert,必须要配置这样一句类似话,否则命令不完整。该句的status 是上一条shell命令退出的状态码,这里即是check.sh执行的结果。
关于status说明,见其他博客,如 https://blog.csdn.net/wlovh1989/article/details/51113488/
还有,可在第19行左右,把每次检查的时间改小一点,例如改成6秒
set daemon 6
在Web界面查看。
默认web界面网址是:localhost:2812
。进入后,输入默认账号admin
,和密码monic
。
即可看到。
可能会报如下错误。
Unable to init server: Could not connect Connection refused Restart… # Failed to parse arguments: Cannot open display.
目前,发现是那句新建终端有问题。即用户没有图形化界面,但尝试去新建一个图形化的终端。
修改方法
第一步,设置环境变量。
export DISPLAY=:0.0
这句可加在start.sh脚本执行新建终端命令之前。
第二步,
需要在终端执行一次这个命令,允许 本机(这里只允许了local) 其它无图形界面的用户,连接当前图形界面。该命令关机后失效。
xhost + local:
若要实现开机就能有这个功能,可以写到开机自启动文件中去。例如/etc/profile
文件。
若要关闭,使用xhost -
即可。
更多与该问题有关的内容,请参见:
https://www.x.org/archive/X11R6.8.1/doc/xhost.1.html
https://www.cnblogs.com/js1314/p/10373332.html
https://blog.csdn.net/u011728480/article/details/66974510
https://www.x.org/archive/X11R6.8.1/doc/xhost.1.html
在测试时,发现这个Watched.out程序启动后,有时候不会退出,不知道是什么鬼问题。定时函数出问题了?在没有关闭Watched.out时,重启monit后,会有一定几率观察到Watched.out一直都没有执行完。
请仔细检查自己的check.sh等脚本程序,并且在本地充分测试,以防不对。
可以在配置文件第20行左右的位置,改成
set daemon 6
with start delay 50
即,启动或重启monit后,第一次会延迟50s后再检查(可防止开机后立即执行造成问题),不开这个选项,会启动monit后,立即检查。然后是每6s定时检查一次。
经测试,那个web服务可以不开,不影响监控程序。但在测试脚本时,开启web服务比较方便。
linux有crond的守护程序,但似乎只能精确到分。
其他的解决方案,如下文记录的
https://www.cnblogs.com/Hackerman/p/3930505.html
https://www.cnblogs.com/Hackerman/p/3932058.html
monit 官方手册
https://www.cnblogs.com/jinjiangongzuoshi/p/3702752.html
https://blog.csdn.net/weixin_33859504/article/details/92009871
https://www.cnblogs.com/kevingrace/p/6322324.html