70 Commits
1.0.8 ... 1.1.0

Author SHA1 Message Date
cppla
d242c6cea1 1.1.0
修复一些bug.
2023-10-09 14:24:17 +08:00
windows11
d7614ab168 width css bt3 2023-10-09 14:08:47 +08:00
windows11
ff06df8263 修复告警信息和URL特殊字符冲突的问题 2023-10-09 13:05:59 +08:00
cppla
9ee1516f72 Update README.md
up theme
2023-10-05 15:29:32 +08:00
cppla
7603ce37af add light theme
add light theme link and demo .
2023-10-05 15:19:02 +08:00
cppla
5cfd533daf flush dns , every time 2023-05-31 11:06:28 +08:00
cppla
9077f1058a add layui theme. 2023-05-04 15:59:37 +08:00
cppla
e34ed05901 make -j,多核心编译docker image 2023-04-12 11:10:10 +08:00
cppla
4ab545f646 fix bug about tupt 2023-04-12 10:17:51 +08:00
cppla
a6b4248967 jquery 3.5.0 to 3.5.1 2023-04-04 19:06:35 +08:00
cppla
8ad927d88d jquery v3.3.1 to v3.5.0 2023-04-03 15:22:59 +08:00
cppla
4b1ec57c6d 增加一个月出口流量示例 2023-04-03 15:12:33 +08:00
cppla
979a9b5d87 加一个ddcc告警示例 2023-03-13 07:23:44 +00:00
cppla
52d62afa59 优化curl 2023-02-28 17:19:49 +08:00
cppla
806b60bd6b get macos infomation build 2022-11-30 11:17:12 +08:00
cppla
d5af5445df disk io not in win 2022-11-30 11:09:21 +08:00
cppla
c77e00476c get macos tudp 2022-11-30 11:02:09 +08:00
cppla
b551998eb8 get macos load 2022-11-30 10:31:04 +08:00
cppla
1c606cc79e update 2022-11-08 12:52:16 +08:00
cppla
d602791b11 macos disk info 2022-11-03 16:38:22 +08:00
cppla
a695ef8b3a update for macos 2022-11-03 16:33:16 +08:00
cppla
9f60b7962b beta macos disk info 2022-11-03 16:25:23 +08:00
cppla
34b1bca5b1 The io_counters is not available on OS X, 兼容处理 2022-11-03 14:49:47 +08:00
cppla
25917f0883 update readme 2022-11-01 13:47:36 +08:00
cppla
333bc29c88 rename old tg to plugin 2022-11-01 13:38:14 +08:00
cppla
c116067c39 get to post 2022-10-31 18:36:33 +08:00
cppla
14db7ec943 update config template 2022-10-31 16:48:54 +08:00
cppla
af8244f1d7 int memory expand 2022-10-31 14:53:12 +08:00
cppla
1004c9a6bd update 2022-10-31 14:25:36 +08:00
cppla
7f78af03f0 100 ping lost 2022-10-31 14:15:37 +08:00
cppla
02bbdb18de update lost style 2022-10-31 14:01:42 +08:00
cppla
6d813f932d Merge pull request #191 from zqcccc/master
展开栏添加丢包信息
2022-10-31 13:43:34 +08:00
c9cu
19d6a5ea8b 展开栏添加丢包信息 2022-10-29 19:07:33 +08:00
cppla
35de279e89 Update README.md 2022-08-26 14:53:47 +08:00
cppla
d5a047c781 Update README.md 2022-08-25 16:23:02 +08:00
cppla
10872059c5 build 1.0.9
build 1.0.9
2022-08-25 16:14:46 +08:00
cppla
44656e565f 更改watchdog callback说明
更改watchdog callback说明
2022-08-25 16:13:24 +08:00
cppla
78c7da7361 经测试邮箱 和wechat不能稳定发送
经测试邮箱 和wechat不能稳定发送
2022-08-25 16:03:46 +08:00
cppla
b5edeea057 Update README.md
添加一个邮箱服务
2022-08-25 14:40:56 +08:00
cppla
c2259f347d Update README.md 2022-08-23 19:39:54 +08:00
cppla
bb5f03047d Update README.md 2022-08-23 19:39:10 +08:00
cppla
6ab6e16d0f 1080 to 1200 2022-08-01 19:37:26 +08:00
cppla
615cec88c2 300s 2022-07-21 10:53:08 +08:00
cppla
94896bac80 change docker to beijing time 2022-07-18 10:36:36 +08:00
cppla
a788b5da90 . 2022-07-17 10:11:11 +08:00
cppla
de0bc9dd74 Update README.md 2022-07-17 10:08:04 +08:00
cppla
ec16fc1fac Update README.md 2022-07-16 19:47:33 +08:00
cppla
cbd803b686 Create README.md
update tips
2022-07-16 19:46:59 +08:00
cppla
3eddb27d51 update 2022-07-16 19:30:29 +08:00
cppla
522809483e Compatible with older versions config.json 2022-07-16 19:11:29 +08:00
cppla
9d706f4da8 Update README.md
update watchdog 说明
2022-07-16 18:44:09 +08:00
cppla
a0fe8ee33c Update README.md
callback说明
2022-07-16 18:35:08 +08:00
cppla
c5eed8e4fa Update README.md
加入watchdog 说明
2022-07-16 18:00:10 +08:00
cppla
32d302580e update 2022-07-16 17:53:17 +08:00
cppla
b03d090a5c update readme 2022-07-16 17:47:57 +08:00
cppla
6151806141 c++ eval build use c++11 2022-07-16 14:42:32 +08:00
cppla
2703993272 add timeout for libcurl 2022-07-16 13:45:37 +08:00
cppla
022e5edb28 formate 2022-07-16 00:41:25 +08:00
cppla
135eb180c8 escape 2022-07-16 00:32:33 +08:00
cppla
2ead43a0d8 update 2022-07-15 23:14:53 +08:00
cppla
baae11de3b tg sms 2022-07-15 22:34:44 +08:00
cppla
2e62ffa593 link libcurl static lib 2022-07-15 21:14:39 +08:00
cppla
f70705d872 next add callback 2022-07-13 17:11:22 +08:00
cppla
7316dbdddb update 2022-07-13 16:55:38 +08:00
cppla
a1689acbf0 trigger msg for watchdog 2022-07-12 16:58:30 +08:00
cppla
e2a59a5465 eval 2022-07-12 15:59:24 +08:00
cppla
962d564c80 copy msg 2022-07-12 13:50:57 +08:00
cppla
77973a5309 0 and 1 2022-07-11 19:03:29 +08:00
cppla
a9128b137d read config. 2022-07-07 18:30:31 +08:00
cppla
0a2a007e24 support for python 3.10 2022-05-30 13:08:34 +08:00
15 changed files with 41176 additions and 152 deletions

View File

@@ -3,13 +3,13 @@ FROM debian:buster as builder
MAINTAINER cppla https://cpp.la
RUN apt-get update -y && apt-get -y install gcc g++ make
RUN apt-get update -y && apt-get -y install gcc g++ make libcurl4-openssl-dev
COPY . .
WORKDIR /server
RUN make
RUN make -j
RUN pwd && ls -a
# glibc env run
@@ -20,6 +20,10 @@ RUN mkdir -p /ServerStatus/server/
COPY --from=builder server /ServerStatus/server/
COPY --from=builder web /usr/share/nginx/html/
# china time
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
EXPOSE 80 35601
CMD nohup sh -c '/etc/init.d/nginx start && /ServerStatus/server/sergate --config=/ServerStatus/server/config.json --web-dir=/usr/share/nginx/html'
CMD nohup sh -c '/etc/init.d/nginx start && /ServerStatus/server/sergate --config=/ServerStatus/server/config.json --web-dir=/usr/share/nginx/html'

140
README.md
View File

@@ -3,16 +3,16 @@
* ServerStatus中文版是一个酷炫高逼格的云探针、云监控、服务器云监控、多服务器探针~。
* 在线演示https://tz.cloudcpp.com
[![Python Support](https://img.shields.io/badge/python-2.7%2B%20-blue.svg)](https://github.com/cppla/ServerStatus)
[![Python Support](https://img.shields.io/badge/python-3.6%2B%20-blue.svg)](https://github.com/cppla/ServerStatus)
[![C++ Compiler](http://img.shields.io/badge/C++-GNU-blue.svg?style=flat&logo=cplusplus)](https://github.com/cppla/ServerStatus)
[![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/cppla/ServerStatus)
[![Version](https://img.shields.io/badge/Version-Beta%201.0.8-red)](https://github.com/cppla/ServerStatus)
[![Version](https://img.shields.io/badge/Version-Build%201.1.0-red)](https://github.com/cppla/ServerStatus)
![Latest Version](http://dl.cpp.la/Archive/serverstatus-latest.png)
![Latest Version](http://dl.cpp.la/Archive/serverstatus_1.0.9.png)
`curl -sSL https://get.docker.com/ | sh && apt -y install docker-compose`
`Watchdog🐶已经加入触发式告警。 interval只是为了防止频繁收到报警信息造成骚扰并不是探测间隔。`
# 目录介绍
# 目录:
* clients 客户端文件
* server 服务端文件
@@ -21,20 +21,17 @@
* server/config.json 探针配置文件      
* web/json 探针月流量
# 自动部署:
# 部署:
【服务端】:
```bash
`OneTouch`:
`Docker`:
wget --no-check-certificate -qO ~/serverstatus-config.json https://raw.githubusercontent.com/cppla/ServerStatus/master/server/config.json && mkdir ~/serverstatus-monthtraffic
docker run -d --restart=always --name=serverstatus -v ~/serverstatus-config.json:/ServerStatus/server/config.json -v ~/serverstatus-monthtraffic:/usr/share/nginx/html/json -p 80:80 -p 35601:35601 cppla/serverstatus:latest
`ServerStatus`: docker-compose up -d
`ServerStatus with tgbot`: TG_CHAT_ID=你的电报ID TG_BOT_TOKEN=你的电报密钥 docker-compose -f docker-compose-telegram.yml up -d
`Docker-compose(推荐)`: docker-compose up -d
```
【客户端】:
@@ -45,27 +42,44 @@ eg:
wget --no-check-certificate -qO client-linux.py 'https://raw.githubusercontent.com/cppla/ServerStatus/master/clients/client-linux.py' && nohup python3 client-linux.py SERVER=45.79.67.132 USER=s04 >/dev/null 2>&1 &
```
# 主题:
* layuihttps://github.com/zeyudada/StatusServerLayui 预览https://sslt.8zyw.cn
<img src=https://dl.cpp.la/Archive/serverstatus_layui.png width=200 height=100 />
* lighthttps://github.com/orilights/ServerStatus-Theme-Light 预览https://tz.cloudcpp.com/index3.html
<img src=https://github.com/orilights/ServerStatus-Theme-Light/blob/main/docs/screenshot.png width=200 height=100 />
# 手动安装教程:
【克隆代码】:
```
git clone https://github.com/cppla/ServerStatus.git
```
【服务端配置】:
**【服务端配置】**
一、生成服务端程序
#### 一、生成服务端程序
```
cd ServerStatus/server
make
`Debian/Ubuntu`: apt-get -y install gcc g++ make libcurl4-openssl-dev
`Centos/Redhat`: yum -y install gcc gcc-c++ make libcurl-devel
cd ServerStatus/server && make
./sergate
```
如果没错误提示OKctrl+c关闭如果有错误提示检查35601端口是否被占用
二、修改配置文件
修改config.json文件注意username, password的值需要和客户端对应一致    
#### 二、修改配置文件
```diff
! watchdog rule 可以为任何已知字段的表达式。
! watchdog interval 最小通知间隔。
! watchdog callback 可自定义为Post方法的URL告警内容将拼接其后并发起回调。
! watchdog callback Telegram: https://api.telegram.org/bot你自己的密钥/sendMessage?parse_mode=HTML&disable_web_page_preview=true&chat_id=你自己的标识&text=
! watchdog callback Server酱: https://sctapi.ftqq.com/你自己的密钥.send?title=ServerStatus&desp=
! watchdog callback PushDeer: https://api2.pushdeer.com/message/push?pushkey=你自己的密钥&text=
! watchdog callback BasicAuth: https://用户名:密码@你自己的域名/api/push?message=
```
{"servers":
```
{
"servers":
[
{
"username": "s01",
@@ -76,55 +90,83 @@ make
"password": "USER_DEFAULT_PASSWORD",
"monthstart": 1
},
],
"watchdog":
[
{
"name": "服务器负载高监控",
"rule": "cpu>90&load_5>3",
"interval": 600,
"callback": "https://yourSMSurl"
},
{
"name": "服务器内存使用率过高监控",
"rule": "(memory_used/memory_total)*100>90",
"interval": 600,
"callback": "https://yourSMSurl"
},
{
"name": "服务器宕机告警,排除经常掉线的",
"rule": "online4=0&online6=0&username!=s21",
"interval": 600,
"callback": "https://yourSMSurl"
},
{
"name": "DDOS和CC攻击监控",
"rule": "tcp_count>600",
"interval": 300,
"callback": "https://yourSMSurl"
},
{
"name": "服务器月出口流量999GB告警",
"rule": "(network_out-last_network_out)/1024/1024/1024>999",
"interval": 3600,
"callback": "https://yourSMSurl"
},
{
"name": "你可以组合任何已知字段的表达式",
"rule": "(hdd_used/hdd_total)*100>95",
"interval": 1800,
"callback": "https://yourSMSurl"
}
]
}
```
三、拷贝ServerStatus/status到你的网站目录
#### 三、拷贝ServerStatus/status到你的网站目录
例如:
```
sudo cp -r ServerStatus/web/* /home/wwwroot/default
```
四、运行服务端:
#### 四、运行服务端:
web-dir参数为上一步设置的网站根目录务必修改成自己网站的路径
```
./sergate --config=config.json --web-dir=/home/wwwroot/default
```
【客户端配置】:
**【客户端配置】**
客户端有两个版本client-linux为普通linuxclient-psutil为跨平台版普通版不成功换成跨平台版即可。
一、client-linux版配置
#### 一、client-linux版配置
1、vim client-linux.py, 修改SERVER地址username帐号 password密码
2、python3 client-linux.py 运行即可。
二、client-psutil版配置:
1、安装psutil跨平台依赖库
#### 二、client-psutil版配置:
1、安装psutil跨平台依赖库
```
`Debian/Ubuntu`: apt -y install python3-pip && pip3 install psutil
`Centos/Redhat`: yum -y install python3-pip gcc python3-devel && pip3 install psutil
`Windows`: https://pypi.org/project/psutil/
```
2、vim client-psutil.py, 修改SERVER地址username帐号 password密码
3、python3 client-psutil.py 运行即可。
```
### for Centos
sudo yum -y install epel-release
sudo yum -y install python3-pip
sudo yum clean all
sudo yum -y install gcc
sudo yum -y install python3-devel
sudo pip3 install psutil
3、python3 client-psutil.py 运行即可。
### for Ubuntu/Debian:
sudo apt -y install python3-pip
sudo pip3 install psutil
### for Windows:
地址https://pypi.org/project/psutil/
下载psutil for windows, 安装即可
```
打开云探针页面,就可以正常的监控。接下来把服务器和客户端脚本自行加入开机启动,或者进程守护,或以后台方式运行即可!例如: nohup python3 client-linux.py &
服务器和客户端自行加入开机启动,或进程守护,或后台方式运行。 例如: nohup python3 client-linux.py &
`extra scene (run web/ssview.py)`
![Shell View](http://dl.cpp.la/Archive/serverstatus-shell.png)
![Shell View](https://dl.cpp.la/Archive/serverstatus-shell.png?version=2023)
# Make Better

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# coding: utf-8
# Update by : https://github.com/cppla/ServerStatus, Update date: 20220323
# 版本1.0.3, 支持Python版本2.7 to 3.9
# Update by : https://github.com/cppla/ServerStatus, Update date: 20220530
# 版本1.0.3, 支持Python版本2.7 to 3.10
# 支持操作系统: Linux, OSX, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures
# 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义例如CU = "www.facebook.com"。
@@ -155,17 +155,18 @@ def _ping_thread(host, mark, port):
lostPacket = 0
packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
IP = host
if host.count(':') < 1: # if not plain ipv6 address, means ipv4 address or hostname
try:
if PROBE_PROTOCOL_PREFER == 'ipv4':
IP = socket.getaddrinfo(host, None, socket.AF_INET)[0][4][0]
else:
IP = socket.getaddrinfo(host, None, socket.AF_INET6)[0][4][0]
except Exception:
while True:
# flush dns , every time.
IP = host
if host.count(':') < 1: # if not plain ipv6 address, means ipv4 address or hostname
try:
if PROBE_PROTOCOL_PREFER == 'ipv4':
IP = socket.getaddrinfo(host, None, socket.AF_INET)[0][4][0]
else:
IP = socket.getaddrinfo(host, None, socket.AF_INET6)[0][4][0]
except Exception:
pass
while True:
if packet_queue.full():
if packet_queue.get() == 0:
lostPacket -= 1
@@ -310,7 +311,7 @@ def get_realtime_data():
target=_disk_io,
)
for ti in [t1, t2, t3, t4, t5]:
ti.setDaemon(True)
ti.daemon = True
ti.start()
def byte_str(object):

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env python3
# coding: utf-8
# Update by : https://github.com/cppla/ServerStatus, Update date: 20220323
# Update by : https://github.com/cppla/ServerStatus, Update date: 20220530
# 依赖于psutil跨平台库
# 版本1.0.3, 支持Python版本2.7 to 3.9
# 版本1.0.3, 支持Python版本2.7 to 3.10
# 支持操作系统: Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures
# 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义例如CU = "www.facebook.com"。
@@ -46,18 +46,22 @@ def get_swap():
return int(Mem.total/1024.0), int(Mem.used/1024.0)
def get_hdd():
valid_fs = [ "ext4", "ext3", "ext2", "reiserfs", "jfs", "btrfs", "fuseblk", "zfs", "simfs", "ntfs", "fat32", "exfat", "xfs" ]
disks = dict()
size = 0
used = 0
for disk in psutil.disk_partitions():
if not disk.device in disks and disk.fstype.lower() in valid_fs:
disks[disk.device] = disk.mountpoint
for disk in disks.values():
usage = psutil.disk_usage(disk)
size += usage.total
used += usage.used
return int(size/1024.0/1024.0), int(used/1024.0/1024.0)
if "darwin" in sys.platform:
return int(psutil.disk_usage("/").total/1024.0/1024.0), int((psutil.disk_usage("/").total-psutil.disk_usage("/").free)/1024.0/1024.0)
else:
valid_fs = ["ext4", "ext3", "ext2", "reiserfs", "jfs", "btrfs", "fuseblk", "zfs", "simfs", "ntfs", "fat32",
"exfat", "xfs"]
disks = dict()
size = 0
used = 0
for disk in psutil.disk_partitions():
if not disk.device in disks and disk.fstype.lower() in valid_fs:
disks[disk.device] = disk.mountpoint
for disk in disks.values():
usage = psutil.disk_usage(disk)
size += usage.total
used += usage.used
return int(size/1024.0/1024.0), int(used/1024.0/1024.0)
def get_cpu():
return psutil.cpu_percent(interval=INTERVAL)
@@ -88,13 +92,23 @@ def tupd():
u = int(os.popen('ss -u|wc -l').read()[:-1])-1
p = int(os.popen('ps -ef|wc -l').read()[:-1])-2
d = int(os.popen('ps -eLf|wc -l').read()[:-1])-2
elif sys.platform.startswith("darwin") is True:
t = int(os.popen('lsof -nP -iTCP | wc -l').read()[:-1]) - 1
u = int(os.popen('lsof -nP -iUDP | wc -l').read()[:-1]) - 1
p = len(psutil.pids())
d = 0
for k in psutil.pids():
try:
d += psutil.Process(k).num_threads()
except:
pass
elif sys.platform.startswith("win") is True:
t = int(os.popen('netstat -an|find "TCP" /c').read()[:-1])-1
u = int(os.popen('netstat -an|find "UDP" /c').read()[:-1])-1
p = len(psutil.pids())
d = 0
# cpu is high, default: 0
# d = sum([psutil.Process(k).num_threads() for k in [x for x in psutil.pids()]])
# if you find cpu is high, please set d=0
d = sum([psutil.Process(k).num_threads() for k in psutil.pids()])
else:
t,u,p,d = 0,0,0,0
return t,u,p,d
@@ -139,17 +153,18 @@ def _ping_thread(host, mark, port):
lostPacket = 0
packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
IP = host
if host.count(':') < 1: # if not plain ipv6 address, means ipv4 address or hostname
try:
if PROBE_PROTOCOL_PREFER == 'ipv4':
IP = socket.getaddrinfo(host, None, socket.AF_INET)[0][4][0]
else:
IP = socket.getaddrinfo(host, None, socket.AF_INET6)[0][4][0]
except Exception:
while True:
# flush dns, every time.
IP = host
if host.count(':') < 1: # if not plain ipv6 address, means ipv4 address or hostname
try:
if PROBE_PROTOCOL_PREFER == 'ipv4':
IP = socket.getaddrinfo(host, None, socket.AF_INET)[0][4][0]
else:
IP = socket.getaddrinfo(host, None, socket.AF_INET6)[0][4][0]
except Exception:
pass
while True:
if packet_queue.full():
if packet_queue.get() == 0:
lostPacket -= 1
@@ -205,44 +220,49 @@ def _disk_io():
比如我这里是机械硬盘,大量做随机小文件读写,那么很低的读写也就能造成硬盘长时间的等待。
如果这里做连续性IO那么普通机械硬盘写入到100Mb/s那么也能造成硬盘长时间的等待。
磁盘读写有误差4k8k https://stackoverflow.com/questions/34413926/psutil-vs-dd-monitoring-disk-i-o
macos/win暂不处理。
"""
while True:
# first get a list of all processes and disk io counters
procs = [p for p in psutil.process_iter()]
for p in procs[:]:
try:
p._before = p.io_counters()
except psutil.Error:
procs.remove(p)
continue
disks_before = psutil.disk_io_counters()
# sleep some time, only when INTERVAL==1 , io read/write per_sec.
# when INTERVAL > 1, io read/write per_INTERVAL
time.sleep(INTERVAL)
# then retrieve the same info again
for p in procs[:]:
with p.oneshot():
if "darwin" in sys.platform or "win" in sys.platform:
diskIO["read"] = 0
diskIO["write"] = 0
else:
while True:
# first get a list of all processes and disk io counters
procs = [p for p in psutil.process_iter()]
for p in procs[:]:
try:
p._after = p.io_counters()
p._cmdline = ' '.join(p.cmdline())
if not p._cmdline:
p._cmdline = p.name()
p._username = p.username()
except (psutil.NoSuchProcess, psutil.ZombieProcess):
p._before = p.io_counters()
except psutil.Error:
procs.remove(p)
disks_after = psutil.disk_io_counters()
continue
disks_before = psutil.disk_io_counters()
# finally calculate results by comparing data before and
# after the interval
for p in procs:
p._read_per_sec = p._after.read_bytes - p._before.read_bytes
p._write_per_sec = p._after.write_bytes - p._before.write_bytes
p._total = p._read_per_sec + p._write_per_sec
# sleep some time, only when INTERVAL==1 , io read/write per_sec.
# when INTERVAL > 1, io read/write per_INTERVAL
time.sleep(INTERVAL)
diskIO["read"] = disks_after.read_bytes - disks_before.read_bytes
diskIO["write"] = disks_after.write_bytes - disks_before.write_bytes
# then retrieve the same info again
for p in procs[:]:
with p.oneshot():
try:
p._after = p.io_counters()
p._cmdline = ' '.join(p.cmdline())
if not p._cmdline:
p._cmdline = p.name()
p._username = p.username()
except (psutil.NoSuchProcess, psutil.ZombieProcess):
procs.remove(p)
disks_after = psutil.disk_io_counters()
# finally calculate results by comparing data before and
# after the interval
for p in procs:
p._read_per_sec = p._after.read_bytes - p._before.read_bytes
p._write_per_sec = p._after.write_bytes - p._before.write_bytes
p._total = p._read_per_sec + p._write_per_sec
diskIO["read"] = disks_after.read_bytes - disks_before.read_bytes
diskIO["write"] = disks_after.write_bytes - disks_before.write_bytes
def get_realtime_data():
'''
@@ -280,7 +300,7 @@ def get_realtime_data():
target=_disk_io,
)
for ti in [t1, t2, t3, t4, t5]:
ti.setDaemon(True)
ti.daemon = True
ti.start()
def byte_str(object):
@@ -344,7 +364,7 @@ if __name__ == '__main__':
CPU = get_cpu()
NET_IN, NET_OUT = liuliang()
Uptime = get_uptime()
Load_1, Load_5, Load_15 = os.getloadavg() if 'linux' in sys.platform else (0.0, 0.0, 0.0)
Load_1, Load_5, Load_15 = os.getloadavg() if 'linux' in sys.platform or 'darwin' in sys.platform else (0.0, 0.0, 0.0)
MemoryTotal, MemoryUsed = get_memory()
SwapTotal, SwapUsed = get_swap()
HDDTotal, HDDUsed = get_hdd()

View File

@@ -2,7 +2,7 @@ version: "3"
services:
serverstatus:
build:
context: .
context: ..
dockerfile: Dockerfile
image: serverstatus_server
container_name: serverstatus
@@ -11,14 +11,14 @@ services:
serverstatus-network:
ipv4_address: 172.23.0.2
volumes:
- ./server/config.json:/ServerStatus/server/config.json
- ./web/json:/usr/share/nginx/html/json
- ../server/config.json:/ServerStatus/server/config.json
- ../web/json:/usr/share/nginx/html/json
ports:
- 35601:35601
- 8080:80
bot:
build:
context: ./plugin
context: .
dockerfile: Dockerfile-telegram
image: serverstatus_bot
container_name: bot4sss

View File

@@ -6,7 +6,7 @@ CFLAGS = -Wall -O2
#CXX = clang++
CXX = g++
CXXFLAGS = -Wall -O2
CXXFLAGS = -Wall -O2 -std=c++11
ODIR = obj
SDIR = src
@@ -26,7 +26,7 @@ $(ODIR)/%.o: $(SDIR)/%.cpp
$(CXX) -c $(INC) $(CXXFLAGS) $< -o $@
$(OUT): $(OBJS)
$(CXX) $(LIBS) $^ -o $(OUT)
$(CXX) $(LIBS) $^ -o $(OUT) -lcurl
.PHONY: clean

View File

@@ -1,5 +1,5 @@
{"servers":
[
{
"servers": [
{
"username": "s01",
"name": "node1",
@@ -22,7 +22,7 @@
"disabled": true,
"username": "s03",
"name": "node3",
"type": "Nothing",
"type": "hyper",
"host": "host3",
"location": "🇫🇷",
"password": "USER_DEFAULT_PASSWORD",
@@ -37,5 +37,43 @@
"password": "USER_DEFAULT_PASSWORD",
"monthstart": 1
}
],
"watchdog": [
{
"name": "cpu high warning",
"rule": "cpu>90&load_1>3",
"interval": 600,
"callback": "https://yourSMSurl"
},
{
"name": "memory high warning",
"rule": "(memory_used/memory_total)*100>90",
"interval": 300,
"callback": "https://yourSMSurl"
},
{
"name": "offline warning",
"rule": "online4=0&online6=0",
"interval": 600,
"callback": "https://yourSMSurl"
},
{
"name": "ddcc attack",
"rule": "tcp_count>500",
"interval": 300,
"callback": "https://yourSMSurl"
},
{
"name": "month traffic warning",
"rule": "(network_out-last_network_out)/1024/1024/1024>999",
"interval": 3600,
"callback": "https://yourSMSurl"
},
{
"name": "you can parse an expression combining any known field",
"rule": "load_5>3",
"interval": 900,
"callback": "https://yourSMSurl"
}
]
}

40746
server/src/exprtk.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,8 @@
#include <json.h>
#include "server.h"
#include "main.h"
#include "exprtk.hpp"
#include "curl/curl.h"
#if defined(CONF_FAMILY_UNIX)
#include <signal.h>
@@ -96,6 +98,13 @@ void CMain::OnDelClient(int ClientNetID)
{
int ClientID = ClientNetToClient(ClientNetID);
dbg_msg("main", "OnDelClient(ncid=%d, cid=%d)", ClientNetID, ClientID);
//copy offline message for watchdog
WatchdogMessage(ClientNetID,
0, 0, 0, 0, 0, 0,
0, 0, 0,0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0,0, 0, 0,
0, 0, 0, 0);
if(ClientID >= 0 && ClientID < NET_MAX_CLIENTS)
{
Client(ClientID)->m_Connected = false;
@@ -191,6 +200,19 @@ int CMain::HandleMessage(int ClientNetID, char *pMessage)
if(rStart["custom"].type == json_string)
str_copy(pClient->m_Stats.m_aCustom, rStart["custom"].u.string.ptr, sizeof(pClient->m_Stats.m_aCustom));
//copy message for watchdog to analysis
WatchdogMessage(ClientNetID,
pClient->m_Stats.m_Load_1, pClient->m_Stats.m_Load_5, pClient->m_Stats.m_Load_15,
pClient->m_Stats.m_ping_10010, pClient->m_Stats.m_ping_189, pClient->m_Stats.m_ping_10086,
pClient->m_Stats.m_time_10010, pClient->m_Stats.m_time_189, pClient->m_Stats.m_time_10086,
pClient->m_Stats.m_tcpCount, pClient->m_Stats.m_udpCount, pClient->m_Stats.m_processCount,
pClient->m_Stats.m_threadCount, pClient->m_Stats.m_NetworkRx, pClient->m_Stats.m_NetworkTx,
pClient->m_Stats.m_NetworkIN, pClient->m_Stats.m_NetworkOUT,pClient->m_Stats.m_MemTotal,
pClient->m_Stats.m_MemUsed, pClient->m_Stats.m_SwapTotal, pClient->m_Stats.m_SwapUsed,
pClient->m_Stats.m_HDDTotal, pClient->m_Stats.m_HDDUsed, pClient->m_Stats.m_IORead,
pClient->m_Stats.m_IOWrite, pClient->m_Stats.m_CPU, pClient->m_Stats.m_Online4,
pClient->m_Stats.m_Online6);
if(m_Config.m_Verbose)
{
if(rStart["online4"].type)
@@ -234,6 +256,113 @@ int CMain::HandleMessage(int ClientNetID, char *pMessage)
return 1;
}
void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086,
double time_10010, double time_189, double time_10086, double tcp_count, double udp_count, double process_count, double thread_count,
double network_rx, double network_tx, double network_in, double network_out, double memory_total, double memory_used,
double swap_total, double swap_used, double hdd_total, double hdd_used, double io_read, double io_write, double cpu,
double online4, double online6)
{
int ID = 0;
while (strcmp(Watchdog(ID)->m_aName, "NULL"))
{
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
const std::string expression_string = Watchdog(ID)->m_aRule;
symbol_table_t symbol_table;
symbol_table.add_variable("load_1",load_1);
symbol_table.add_variable("load_5",load_5);
symbol_table.add_variable("load_15",load_15);
symbol_table.add_variable("ping_10010",ping_10010);
symbol_table.add_variable("ping_189",ping_189);
symbol_table.add_variable("ping_10086",ping_10086);
symbol_table.add_variable("time_10010",time_10010);
symbol_table.add_variable("time_189",time_189);
symbol_table.add_variable("time_10086",time_10086);
symbol_table.add_variable("tcp_count",tcp_count);
symbol_table.add_variable("udp_count",udp_count);
symbol_table.add_variable("process_count",process_count);
symbol_table.add_variable("thread_count",thread_count);
symbol_table.add_variable("network_rx",network_rx);
symbol_table.add_variable("network_tx",network_tx);
symbol_table.add_variable("network_in",network_in);
symbol_table.add_variable("network_out",network_out);
symbol_table.add_variable("memory_total",memory_total);
symbol_table.add_variable("memory_used",memory_used);
symbol_table.add_variable("swap_total",swap_total);
symbol_table.add_variable("swap_used",swap_used);
symbol_table.add_variable("hdd_total",hdd_total);
symbol_table.add_variable("hdd_used",hdd_used);
symbol_table.add_variable("io_read",io_read);
symbol_table.add_variable("io_write",io_write);
symbol_table.add_variable("cpu",cpu);
symbol_table.add_variable("online4",online4);
symbol_table.add_variable("online6",online6);
symbol_table.add_constants();
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
parser.compile(expression_string,expression);
if (expression.value() > 0)
{
int ClientID = ClientNetToClient(ClientNetID);
time_t currentStamp = (long long)time(/*ago*/0);
if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > Watchdog(ID)->m_aInterval)
{
Client(ClientID)->m_AlarmLastTime = currentStamp;
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl) {
//standard time
char standardTime[32]= { 0 };
strftime(standardTime, sizeof(standardTime), "%Y-%m-%d %H:%M:%S",localtime(&currentStamp));
//url encode, Rules conflict with url special characterseg&, del rules, by https://cpp.la, 2023-10-09
char encodeBuffer[2048] = { 0 };
sprintf(encodeBuffer, "【告警名称】 %s \n\n【告警时间】 %s \n\n【用户名】 %s \n\n【节点名】 %s \n\n【虚拟化】 %s \n\n【主机名】 %s \n\n【位 置】 %s",
Watchdog(ID)->m_aName,
standardTime,
Client(ClientID)->m_aUsername,
Client(ClientID)->m_aName,
Client(ClientID)->m_aType,
Client(ClientID)->m_aHost,
Client(ClientID)->m_aLocation);
char *encodeUrl = curl_easy_escape(curl, encodeBuffer, strlen(encodeBuffer));
//standard url
char urlBuffer[2048] = { 0 };
sprintf(urlBuffer, "%s%s",Watchdog(ID)->m_aCallback, encodeUrl);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_URL, urlBuffer);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,"signature=ServerStatus");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6L);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "watchdog failed: %s\n", curl_easy_strerror(res));
if(encodeUrl)
curl_free(encodeUrl);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
}
ID++;
}
}
void CMain::JSONUpdateThread(void *pUser)
{
CJSONUpdateThreadData *m_pJSONUpdateThreadData = (CJSONUpdateThreadData *)pUser;
@@ -411,6 +540,28 @@ int CMain::ReadConfig()
}
}
// watch dog
// support by: https://cpp.la
ID = 0;
const json_value &jStart = (*pJsonData)["watchdog"];
if(jStart.type == json_array)
{
for(unsigned i = 0; i < jStart.u.array.length; i++)
{
if(ID < 0 || ID >= NET_MAX_CLIENTS)
continue;
str_copy(Watchdog(ID)->m_aName, jStart[i]["name"].u.string.ptr, sizeof(Watchdog(ID)->m_aName));
str_copy(Watchdog(ID)->m_aRule, jStart[i]["rule"].u.string.ptr, sizeof(Watchdog(ID)->m_aRule));
Watchdog(ID)->m_aInterval = jStart[i]["interval"].u.integer;
str_copy(Watchdog(ID)->m_aCallback, jStart[i]["callback"].u.string.ptr, sizeof(Watchdog(ID)->m_aCallback));
ID++;
}
str_copy(Watchdog(ID)->m_aName, "NULL", sizeof(Watchdog(ID)->m_aName));
} else
str_copy(Watchdog(ID)->m_aName, "NULL", sizeof(Watchdog(ID)->m_aName));
// if file exists, read last network traffic recordreset m_LastNetworkIN and m_LastNetworkOUT
// support by: https://cpp.la
IOHANDLE nFile = io_open(m_Config.m_aJSONFile, IOFLAG_READ);
@@ -566,3 +717,4 @@ int main(int argc, const char *argv[])
return RetVal;
}

View File

@@ -38,10 +38,11 @@ class CMain
char m_aPassword[128];
int m_aMonthStart; //track month network traffic. by: https://cpp.la
int64_t m_LastNetworkIN;
int64_t m_LastNetworkOUT;
int64 m_TimeConnected;
int64 m_LastUpdate;
int64_t m_LastNetworkIN; //restore month traffic info.
int64_t m_LastNetworkOUT; //restore month traffic info.
int64_t m_TimeConnected;
int64_t m_LastUpdate;
int64_t m_AlarmLastTime; //record last alarm time.
struct CStats
{
@@ -82,6 +83,13 @@ class CMain
} m_Stats;
} m_aClients[NET_MAX_CLIENTS];
struct CWatchDog{
char m_aName[128];
char m_aRule[128];
int m_aInterval;
char m_aCallback[1024];
} m_aCWatchDogs[NET_MAX_CLIENTS];
struct CJSONUpdateThreadData
{
CClient *pClients;
@@ -99,6 +107,14 @@ public:
int ReadConfig();
int Run();
CWatchDog *Watchdog(int ruleID) { return &m_aCWatchDogs[ruleID]; }
void WatchdogMessage(int ClientNetID,
double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086,
double time_10010, double time_189, double time_10086, double tcp_count, double udp_count, double process_count, double thread_count,
double network_rx, double network_tx, double network_in, double network_out,double memory_total,
double memory_used,double swap_total, double swap_used, double hdd_total,
double hdd_used, double io_read, double io_write, double cpu,double online4, double online6);
CClient *Client(int ClientID) { return &m_aClients[ClientID]; }
CClient *ClientNet(int ClientNetID);
const CConfig *Config() const { return &m_Config; }

File diff suppressed because one or more lines are too long

View File

@@ -6,6 +6,7 @@ body { background: #212e36 url('../img/dark.png'); color: #dcdcdc; }
.dropdown-menu > li > a:hover { color: #FFF !important; background: #000 !important; }
.dropdown-menu { background: #222 !important; background-color: #222222 !important; }
.navbar-inverse .navbar-inner { background-color:#1B1B1B; background-image:-moz-linear-gradient(top, #222222, #111111); background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); background-image:-webkit-linear-gradient(top, #222222, #111111); background-image:-o-linear-gradient(top, #222222, #111111); background-image:linear-gradient(to bottom, #212e36, #212e36); background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); border-color: #252525; }
.container { width: 1280px; }
.content { background: #212e36; padding: 20px; border-radius: 5px; border: 1px #212e36 solid; -webkit-box-shadow: 0 0px 0px rgba(0, 0, 0, 0); -moz-box-shadow: 0 0px 0px rgba(0, 0, 0, 0); box-shadow: 0 0px 0px rgba(0, 0, 0, 0); margin-bottom: 20px; }
.table { background: #363b40; margin-bottom: 0; border-collapse: collapse; border-radius: 3px; }
.table th { text-align: center; }
@@ -18,11 +19,11 @@ tr.even.expandRow > :hover { background: #212e36 !important; }
tr.odd.expandRow > :hover { background: #212e36 !important; }
.expandRow > td { padding: 0 !important; border-top: 0px !important; }
#month_traffic { min-width: 85px; max-width: 95px;}
#network { min-width: 115px; }
#network { min-width: 110px; }
#cpu, #ram, #hdd { min-width: 45px; max-width: 90px; }
#ping { max-width: 95px; }
#ping { max-width: 110px; }
@media only screen and (max-width: 1080px) {
@media only screen and (max-width: 1200px) {
#type, tr td:nth-child(4) { display:none; visibility:hidden; }
#location, tr td:nth-child(5) { display:none; visibility:hidden; }
#uptime, tr td:nth-child(6) { display:none; visibility:hidden; }

View File

@@ -3,6 +3,7 @@ body { background: #ebebeb url('../img/light.png'); }
.navbar-brand { color: #fff; padding: 10px; font-size: 20px; }
.dropdown .dropdown-toggle { padding-bottom: 10px; padding-top: 10px; }
.navbar-inverse .navbar-brand { color: #fff; padding: 10px; font-size: 20px; }
.container { width: 1280px; }
.content { background: #ffffff; padding: 20px; border-radius: 5px; border: 1px #cecece solid; -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, .1); -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, .1); box-shadow: 0 1px 10px rgba(0, 0, 0, .1); margin-bottom: 20px; }
.table { background: #ffffff; margin-bottom: 0; border-collapse: collapse; border-radius: 3px; }
.table th, .table td { text-align: center; }
@@ -15,11 +16,11 @@ tr.even.expandRow > :hover { background: #F9F9F9 !important; }
tr.odd.expandRow > :hover { background: #FFF !important; }
.expandRow > td { padding: 0 !important; border-top: 0px !important; }
#month_traffic { min-width: 85px; max-width: 95px;}
#network { min-width: 115px; }
#network { min-width: 110px; }
#cpu, #ram, #hdd { min-width: 45px; max-width: 90px; }
#ping { max-width: 95px; }
#ping { max-width: 110px; }
@media only screen and (max-width: 1080px) {
@media only screen and (max-width: 1200px) {
#type, tr td:nth-child(4) { display:none; visibility:hidden; }
#location, tr td:nth-child(5) { display:none; visibility:hidden; }
#uptime, tr td:nth-child(6) { display:none; visibility:hidden; }

File diff suppressed because one or more lines are too long

View File

@@ -79,10 +79,10 @@ function uptime() {
"</tr>" +
"<tr class=\"expandRow " + hack + "\"><td colspan=\"16\"><div class=\"accordian-body collapse\" id=\"rt" + i + "\">" +
"<div id=\"expand_mem\">加载中</div>" +
"<div id=\"expand_swap\">加载中</div>" +
"<div id=\"expand_hdd\">加载中</div>" +
"<div id=\"expand_tupd\">加载中</div>" +
"<div id=\"expand_ping\">加载中</div>" +
"<div id=\"expand_lost\">加载中</div>" +
"<div id=\"expand_custom\">加载中</div>" +
"</div></td></tr>"
);
@@ -223,9 +223,8 @@ function uptime() {
TableRow.children["memory"].children[0].children[0].className = "progress-bar progress-bar-success";
TableRow.children["memory"].children[0].children[0].style.width = Mem + "%";
TableRow.children["memory"].children[0].children[0].innerHTML = Mem + "%";
ExpandRow[0].children["expand_mem"].innerHTML = "内存: " + bytesToSize(result.servers[i].memory_used*1024, 2) + " / " + bytesToSize(result.servers[i].memory_total*1024, 2);
// Swap
ExpandRow[0].children["expand_swap"].innerHTML = "交换分区: " + bytesToSize(result.servers[i].swap_used*1024, 2) + " / " + bytesToSize(result.servers[i].swap_total*1024, 2);
// 内存|swap
ExpandRow[0].children["expand_mem"].innerHTML = "内存|虚存: " + bytesToSize(result.servers[i].memory_used*1024, 1) + " / " + bytesToSize(result.servers[i].memory_total*1024, 1) + " | " + bytesToSize(result.servers[i].swap_used*1024, 0) + " / " + bytesToSize(result.servers[i].swap_total*1024, 0);
// HDD
var HDD = ((result.servers[i].hdd_used/result.servers[i].hdd_total)*100.0).toFixed(0);
@@ -262,8 +261,12 @@ function uptime() {
var PING_10010 = result.servers[i].ping_10010.toFixed(0);
var PING_189 = result.servers[i].ping_189.toFixed(0);
var PING_10086 = result.servers[i].ping_10086.toFixed(0);
ExpandRow[0].children["expand_lost"].innerHTML = "丢包:联通/电信/移动: " + PING_10010 + "% / " + PING_189 + "% / " + PING_10086 + "%"
if (PING_10010 >= 20 || PING_189 >= 20 || PING_10086 >= 20)
TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-warning";
TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-danger";
else if (PING_10010 >= 10 || PING_189 >= 10 || PING_10086 >= 10)
TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-warning";
else
TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-success";
TableRow.children["ping"].children[0].children[0].innerHTML = PING_10010 + "%💻" + PING_189 + "%💻" + PING_10086 + "%";