mirror of
https://github.com//cppla/ServerStatus
synced 2025-07-04 00:16:00 +08:00
Compare commits
62 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
830938eac9 | ||
|
1a764ed104 | ||
|
b0c543b44b | ||
|
f85c0a87f9 | ||
|
67d7c5ea0f | ||
|
8576f81404 | ||
|
fa0ee2bf57 | ||
|
e9776b0e69 | ||
|
e01cc118dc | ||
|
784c40b153 | ||
|
6068a2ba17 | ||
|
ced526824f | ||
|
7d2a73bf2e | ||
|
51e2f664cd | ||
|
937b1ea90f | ||
|
b95d1945bf | ||
|
e8446cd52f | ||
|
6098f0fb1a | ||
|
fc89a76cc2 | ||
|
f290947b2c | ||
|
b3adc6b782 | ||
|
705a957606 | ||
|
a307ad7d19 | ||
|
ad95e00723 | ||
|
31330168f3 | ||
|
d9e8f8a7c1 | ||
|
08f15ebdc5 | ||
|
adb05818b9 | ||
|
4e73e8185e | ||
|
0fe01064a4 | ||
|
510567eaec | ||
|
503037c7e2 | ||
|
d75d5438a3 | ||
|
91f11dad76 | ||
|
fdc5abacfc | ||
|
388938e02b | ||
|
f912794068 | ||
|
6331d7d45b | ||
|
25f878a38a | ||
|
a8b9b2d00d | ||
|
dc3868998a | ||
|
75d06c8666 | ||
|
360252182d | ||
|
aa0ccd254c | ||
|
f7b2e7db42 | ||
|
052c75ef23 | ||
|
1f7827cc21 | ||
|
c236aee5dc | ||
|
fb3ecd1796 | ||
|
810f6a0d8a | ||
|
eddf37c413 | ||
|
8dfc6d4718 | ||
|
03446b8f29 | ||
|
6ab046be51 | ||
|
94708c588c | ||
|
144987bcf1 | ||
|
7e46b1062e | ||
|
71cadcfebe | ||
|
d96e711a34 | ||
|
5ebf076330 | ||
|
4a9f5adb6b | ||
|
59fa2d8eab |
10
Dockerfile
10
Dockerfile
@ -1,7 +1,7 @@
|
|||||||
# The Dockerfile for build localhost source, not git repo
|
# The Dockerfile for build localhost source, not git repo
|
||||||
FROM debian:buster as builder
|
FROM debian:buster AS builder
|
||||||
|
|
||||||
MAINTAINER cppla https://cpp.la
|
LABEL maintainer="cppla <https://cpp.la>"
|
||||||
|
|
||||||
RUN apt-get update -y && apt-get -y install gcc g++ make libcurl4-openssl-dev
|
RUN apt-get update -y && apt-get -y install gcc g++ make libcurl4-openssl-dev
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ RUN pwd && ls -a
|
|||||||
# glibc env run
|
# glibc env run
|
||||||
FROM nginx:latest
|
FROM nginx:latest
|
||||||
|
|
||||||
RUN mkdir -p /ServerStatus/server/
|
RUN mkdir -p /ServerStatus/server/ && ln -sf /dev/null /var/log/nginx/access.log && ln -sf /dev/null /var/log/nginx/error.log
|
||||||
|
|
||||||
COPY --from=builder server /ServerStatus/server/
|
COPY --from=builder server /ServerStatus/server/
|
||||||
COPY --from=builder web /usr/share/nginx/html/
|
COPY --from=builder web /usr/share/nginx/html/
|
||||||
@ -25,5 +25,5 @@ ENV TZ=Asia/Shanghai
|
|||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
|
||||||
EXPOSE 80 35601
|
EXPOSE 80 35601
|
||||||
|
HEALTHCHECK --interval=5s --timeout=3s --retries=3 CMD curl --fail http://localhost:80 || bash -c 'kill -s 15 -1 && (sleep 10; kill -s 9 -1)'
|
||||||
CMD nohup sh -c '/etc/init.d/nginx start && /ServerStatus/server/sergate --config=/ServerStatus/server/config.json --web-dir=/usr/share/nginx/html'
|
CMD ["sh", "-c", "/etc/init.d/nginx start && /ServerStatus/server/sergate --config=/ServerStatus/server/config.json --web-dir=/usr/share/nginx/html"]
|
62
README.md
62
README.md
@ -1,16 +1,16 @@
|
|||||||
# ServerStatus中文版:
|
# ServerStatus中文版:
|
||||||
|
|
||||||
* ServerStatus中文版是一个酷炫高逼格的云探针、云监控、服务器云监控、多服务器探针~。
|
* ServerStatus中文版是一个酷炫高逼格的云探针、云监控、服务器云监控、多服务器探针~。。
|
||||||
* 在线演示:https://tz.cloudcpp.com
|
* 在线演示:https://tz.cloudcpp.com
|
||||||
|
|
||||||
[](https://github.com/cppla/ServerStatus)
|
[](https://github.com/cppla/ServerStatus)
|
||||||
[](https://github.com/cppla/ServerStatus)
|
[](https://github.com/cppla/ServerStatus)
|
||||||
[](https://github.com/cppla/ServerStatus)
|
[](https://github.com/cppla/ServerStatus)
|
||||||
[](https://github.com/cppla/ServerStatus)
|
[](https://github.com/cppla/ServerStatus)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
`Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。 同时为了防止海外机器闪断报警,也加入username、name、type等静态字符串参数的计算支持。`
|
`Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。值得注意的是,Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复。 `
|
||||||
|
|
||||||
# 目录:
|
# 目录:
|
||||||
|
|
||||||
@ -67,14 +67,14 @@ cd ServerStatus/server && make
|
|||||||
|
|
||||||
#### 二、修改配置文件
|
#### 二、修改配置文件
|
||||||
```diff
|
```diff
|
||||||
! watchdog rule 可以为任何已知字段的表达式
|
! watchdog rule 可以为任何已知字段的表达式。注意Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复
|
||||||
! watchdog interval 最小通知间隔
|
! watchdog interval 最小通知间隔
|
||||||
! watchdog callback 可自定义为Post方法的URL,告警内容将拼接其后并发起回调
|
! watchdog callback 可自定义为Post方法的URL,告警内容将拼接其后并发起回调
|
||||||
|
|
||||||
! watchdog callback Telegram: https://api.telegram.org/bot你自己的密钥/sendMessage?parse_mode=HTML&disable_web_page_preview=true&chat_id=你自己的标识&text=
|
! 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=
|
! Server酱: https://sctapi.ftqq.com/你自己的密钥.send?title=ServerStatus&desp=
|
||||||
! watchdog callback PushDeer: https://api2.pushdeer.com/message/push?pushkey=你自己的密钥&text=
|
! PushDeer: https://api2.pushdeer.com/message/push?pushkey=你自己的密钥&text=
|
||||||
! watchdog callback BasicAuth: https://用户名:密码@你自己的域名/api/push?message=
|
! HttpBasicAuth: https://用户名:密码@你自己的域名/api/push?message=
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -89,31 +89,45 @@ cd ServerStatus/server && make
|
|||||||
"location": "🇨🇳",
|
"location": "🇨🇳",
|
||||||
"password": "USER_DEFAULT_PASSWORD",
|
"password": "USER_DEFAULT_PASSWORD",
|
||||||
"monthstart": 1
|
"monthstart": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"monitors": [
|
||||||
|
{
|
||||||
|
"name": "监测网站,默认为一天在线率",
|
||||||
|
"host": "https://www.baidu.com",
|
||||||
|
"interval": 1200,
|
||||||
|
"type": "https"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "监测tcp服务端口",
|
||||||
|
"host": "1.1.1.1:80",
|
||||||
|
"interval": 1200,
|
||||||
|
"type": "tcp"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"watchdog":
|
"watchdog":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "服务器负载高监控,排除内存大于32G物理机,同时排除俄勒冈机器",
|
"name": "服务器负载高监控,排除内存大于32G物理机,同时排除node1机器",
|
||||||
"rule": "cpu>90&load_1>4&memory_total<33554432&name!='俄勒冈'",
|
"rule": "cpu>90&load_1>4&memory_total<33554432&name!='node1'",
|
||||||
"interval": 600,
|
"interval": 600,
|
||||||
"callback": "https://yourSMSurl"
|
"callback": "https://yourSMSurl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "服务器内存使用率过高监控",
|
"name": "服务器内存使用率过高监控,排除小于1G的机器",
|
||||||
"rule": "(memory_used/memory_total)*100>90",
|
"rule": "(memory_used/memory_total)*100>90&memory_total>1048576",
|
||||||
"interval": 600,
|
"interval": 600,
|
||||||
"callback": "https://yourSMSurl"
|
"callback": "https://yourSMSurl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "服务器宕机告警,排出俄勒冈,排除s02",
|
"name": "服务器宕机告警",
|
||||||
"rule": "online4=0&online6=0&name!='俄勒冈'&username!='s02'",
|
"rule": "online4=0&online6=0",
|
||||||
"interval": 600,
|
"interval": 600,
|
||||||
"callback": "https://yourSMSurl"
|
"callback": "https://yourSMSurl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "DDOS和CC攻击监控",
|
"name": "DDOS和CC攻击监控,限制甲骨文机器",
|
||||||
"rule": "tcp_count>600",
|
"rule": "tcp_count>600&type='Oracle'",
|
||||||
"interval": 300,
|
"interval": 300,
|
||||||
"callback": "https://yourSMSurl"
|
"callback": "https://yourSMSurl"
|
||||||
},
|
},
|
||||||
@ -123,6 +137,18 @@ cd ServerStatus/server && make
|
|||||||
"interval": 3600,
|
"interval": 3600,
|
||||||
"callback": "https://yourSMSurl"
|
"callback": "https://yourSMSurl"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "阿里云服务器流量18GB告警,限制username为乌兰察布",
|
||||||
|
"rule": "(network_out-last_network_out)/1024/1024/1024>18&(username='wlcb1'|username='wlcb2'|username='wlcb3'|username='wlcb4')",
|
||||||
|
"interval": 3600,
|
||||||
|
"callback": "https://yourSMSurl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "重要线路丢包率过高检查",
|
||||||
|
"rule": "(ping_10010>10|ping_189>10|ping_10086>10)&(host='sgp'|host='qqhk'|host='hk-21-x'|host='hk-31-x')",
|
||||||
|
"interval": 600,
|
||||||
|
"callback": "https://yourSMSurl"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "你可以组合任何已知字段的表达式",
|
"name": "你可以组合任何已知字段的表达式",
|
||||||
"rule": "(hdd_used/hdd_total)*100>95",
|
"rule": "(hdd_used/hdd_total)*100>95",
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
# Update by : https://github.com/cppla/ServerStatus, Update date: 20220530
|
# Update by : https://github.com/cppla/ServerStatus, Update date: 20220530
|
||||||
# 版本:1.0.3, 支持Python版本:2.7 to 3.10
|
# 版本:1.0.3, 支持Python版本:2.7 to 3.10
|
||||||
# 支持操作系统: Linux, OSX, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures
|
# 支持操作系统: Linux, OSX, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures
|
||||||
|
# ONLINE_PACKET_HISTORY_LEN, 探测间隔1200s,记录24小时在线率(72);探测时间300s,记录24小时(288);探测间隔60s,记录7天(10080)
|
||||||
# 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。
|
# 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。
|
||||||
|
|
||||||
SERVER = "127.0.0.1"
|
SERVER = "127.0.0.1"
|
||||||
@ -17,9 +18,11 @@ CM = "cm.tz.cloudcpp.com"
|
|||||||
PROBEPORT = 80
|
PROBEPORT = 80
|
||||||
PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6
|
PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6
|
||||||
PING_PACKET_HISTORY_LEN = 100
|
PING_PACKET_HISTORY_LEN = 100
|
||||||
|
ONLINE_PACKET_HISTORY_LEN = 72
|
||||||
INTERVAL = 1
|
INTERVAL = 1
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
|
import ssl
|
||||||
import time
|
import time
|
||||||
import timeit
|
import timeit
|
||||||
import re
|
import re
|
||||||
@ -29,10 +32,10 @@ import json
|
|||||||
import errno
|
import errno
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
try:
|
if sys.version_info.major == 3:
|
||||||
from queue import Queue # python3
|
from queue import Queue
|
||||||
except ImportError:
|
elif sys.version_info.major == 2:
|
||||||
from Queue import Queue # python2
|
from Queue import Queue
|
||||||
|
|
||||||
def get_uptime():
|
def get_uptime():
|
||||||
with open('/proc/uptime', 'r') as f:
|
with open('/proc/uptime', 'r') as f:
|
||||||
@ -150,6 +153,7 @@ diskIO = {
|
|||||||
'read': 0,
|
'read': 0,
|
||||||
'write': 0
|
'write': 0
|
||||||
}
|
}
|
||||||
|
monitorServer = {}
|
||||||
|
|
||||||
def _ping_thread(host, mark, port):
|
def _ping_thread(host, mark, port):
|
||||||
lostPacket = 0
|
lostPacket = 0
|
||||||
@ -314,6 +318,91 @@ def get_realtime_data():
|
|||||||
ti.daemon = True
|
ti.daemon = True
|
||||||
ti.start()
|
ti.start()
|
||||||
|
|
||||||
|
|
||||||
|
def _monitor_thread(name, host, interval, type):
|
||||||
|
lostPacket = 0
|
||||||
|
packet_queue = Queue(maxsize=ONLINE_PACKET_HISTORY_LEN)
|
||||||
|
while True:
|
||||||
|
if name not in monitorServer.keys():
|
||||||
|
break
|
||||||
|
if packet_queue.full():
|
||||||
|
if packet_queue.get() == 0:
|
||||||
|
lostPacket -= 1
|
||||||
|
try:
|
||||||
|
if type == "http":
|
||||||
|
address = host.replace("http://", "")
|
||||||
|
m = timeit.default_timer()
|
||||||
|
if PROBE_PROTOCOL_PREFER == 'ipv4':
|
||||||
|
IP = socket.getaddrinfo(address, None, socket.AF_INET)[0][4][0]
|
||||||
|
else:
|
||||||
|
IP = socket.getaddrinfo(address, None, socket.AF_INET6)[0][4][0]
|
||||||
|
monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
k = socket.create_connection((IP, 80), timeout=6)
|
||||||
|
monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
k.sendall("GET / HTTP/1.2\r\nHost:{}\r\nUser-Agent:ServerStatus/cppla\r\nConnection:close\r\n\r\n".format(address).encode('utf-8'))
|
||||||
|
response = b""
|
||||||
|
while True:
|
||||||
|
data = k.recv(4096)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
response += data
|
||||||
|
http_code = response.decode('utf-8').split('\r\n')[0].split()[1]
|
||||||
|
monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
k.close()
|
||||||
|
if http_code not in ['200', '204', '301', '302', '401']:
|
||||||
|
raise Exception("http code not in 200, 204, 301, 302, 401")
|
||||||
|
elif type == "https":
|
||||||
|
context = ssl._create_unverified_context()
|
||||||
|
address = host.replace("https://", "")
|
||||||
|
m = timeit.default_timer()
|
||||||
|
if PROBE_PROTOCOL_PREFER == 'ipv4':
|
||||||
|
IP = socket.getaddrinfo(address, None, socket.AF_INET)[0][4][0]
|
||||||
|
else:
|
||||||
|
IP = socket.getaddrinfo(address, None, socket.AF_INET6)[0][4][0]
|
||||||
|
monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
k = socket.create_connection((IP, 443), timeout=6)
|
||||||
|
monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
kk = context.wrap_socket(k, server_hostname=address)
|
||||||
|
kk.sendall("GET / HTTP/1.2\r\nHost:{}\r\nUser-Agent:ServerStatus/cppla\r\nConnection:close\r\n\r\n".format(address).encode('utf-8'))
|
||||||
|
response = b""
|
||||||
|
while True:
|
||||||
|
data = kk.recv(4096)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
response += data
|
||||||
|
http_code = response.decode('utf-8').split('\r\n')[0].split()[1]
|
||||||
|
monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
kk.close()
|
||||||
|
k.close()
|
||||||
|
if http_code not in ['200', '204', '301', '302', '401']:
|
||||||
|
raise Exception("http code not in 200, 204, 301, 302, 401")
|
||||||
|
elif type == "tcp":
|
||||||
|
m = timeit.default_timer()
|
||||||
|
if PROBE_PROTOCOL_PREFER == 'ipv4':
|
||||||
|
IP = socket.getaddrinfo(host.split(":")[0], None, socket.AF_INET)[0][4][0]
|
||||||
|
else:
|
||||||
|
IP = socket.getaddrinfo(host.split(":")[0], None, socket.AF_INET6)[0][4][0]
|
||||||
|
monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
k = socket.create_connection((IP, int(host.split(":")[1])), timeout=6)
|
||||||
|
monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
k.send(b"GET / HTTP/1.2\r\n\r\n")
|
||||||
|
k.recv(1024)
|
||||||
|
monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
k.close()
|
||||||
|
packet_queue.put(1)
|
||||||
|
except Exception as e:
|
||||||
|
lostPacket += 1
|
||||||
|
packet_queue.put(0)
|
||||||
|
if packet_queue.qsize() > 5:
|
||||||
|
monitorServer[name]["online_rate"] = 1 - float(lostPacket) / packet_queue.qsize()
|
||||||
|
time.sleep(interval)
|
||||||
|
|
||||||
def byte_str(object):
|
def byte_str(object):
|
||||||
'''
|
'''
|
||||||
bytes to str, str to bytes
|
bytes to str, str to bytes
|
||||||
@ -360,6 +449,28 @@ if __name__ == '__main__':
|
|||||||
if data.find("You are connecting via") < 0:
|
if data.find("You are connecting via") < 0:
|
||||||
data = byte_str(s.recv(1024))
|
data = byte_str(s.recv(1024))
|
||||||
print(data)
|
print(data)
|
||||||
|
monitorServer.clear()
|
||||||
|
for i in data.split('\n'):
|
||||||
|
if "monitor" in i and "type" in i and "{" in i and "}" in i:
|
||||||
|
jdata = json.loads(i[i.find("{"):i.find("}")+1])
|
||||||
|
monitorServer[jdata.get("name")] = {
|
||||||
|
"type": jdata.get("type"),
|
||||||
|
"dns_time": 0,
|
||||||
|
"connect_time": 0,
|
||||||
|
"download_time": 0,
|
||||||
|
"online_rate": 1
|
||||||
|
}
|
||||||
|
t = threading.Thread(
|
||||||
|
target=_monitor_thread,
|
||||||
|
kwargs={
|
||||||
|
'name': jdata.get("name"),
|
||||||
|
'host': jdata.get("host"),
|
||||||
|
'interval': jdata.get("interval"),
|
||||||
|
'type': jdata.get("type")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
|
||||||
timer = 0
|
timer = 0
|
||||||
check_ip = 0
|
check_ip = 0
|
||||||
@ -378,7 +489,6 @@ if __name__ == '__main__':
|
|||||||
Load_1, Load_5, Load_15 = os.getloadavg()
|
Load_1, Load_5, Load_15 = os.getloadavg()
|
||||||
MemoryTotal, MemoryUsed, SwapTotal, SwapFree = get_memory()
|
MemoryTotal, MemoryUsed, SwapTotal, SwapFree = get_memory()
|
||||||
HDDTotal, HDDUsed = get_hdd()
|
HDDTotal, HDDUsed = get_hdd()
|
||||||
|
|
||||||
array = {}
|
array = {}
|
||||||
if not timer:
|
if not timer:
|
||||||
array['online' + str(check_ip)] = get_network(check_ip)
|
array['online' + str(check_ip)] = get_network(check_ip)
|
||||||
@ -401,8 +511,6 @@ if __name__ == '__main__':
|
|||||||
array['network_tx'] = netSpeed.get("nettx")
|
array['network_tx'] = netSpeed.get("nettx")
|
||||||
array['network_in'] = NET_IN
|
array['network_in'] = NET_IN
|
||||||
array['network_out'] = NET_OUT
|
array['network_out'] = NET_OUT
|
||||||
# todo:兼容旧版本,下个版本删除ip_status
|
|
||||||
array['ip_status'] = True
|
|
||||||
array['ping_10010'] = lostRate.get('10010') * 100
|
array['ping_10010'] = lostRate.get('10010') * 100
|
||||||
array['ping_189'] = lostRate.get('189') * 100
|
array['ping_189'] = lostRate.get('189') * 100
|
||||||
array['ping_10086'] = lostRate.get('10086') * 100
|
array['ping_10086'] = lostRate.get('10086') * 100
|
||||||
@ -412,16 +520,18 @@ if __name__ == '__main__':
|
|||||||
array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
|
array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
|
||||||
array['io_read'] = diskIO.get("read")
|
array['io_read'] = diskIO.get("read")
|
||||||
array['io_write'] = diskIO.get("write")
|
array['io_write'] = diskIO.get("write")
|
||||||
|
array['custom'] = "<br>".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: <code>{v['online_rate']*100:.1f}%</code>" for k, v in monitorServer.items())
|
||||||
s.send(byte_str("update " + json.dumps(array) + "\n"))
|
s.send(byte_str("update " + json.dumps(array) + "\n"))
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
except socket.error:
|
except socket.error:
|
||||||
|
monitorServer.clear()
|
||||||
print("Disconnected...")
|
print("Disconnected...")
|
||||||
if 's' in locals().keys():
|
if 's' in locals().keys():
|
||||||
del s
|
del s
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
monitorServer.clear()
|
||||||
print("Caught Exception:", e)
|
print("Caught Exception:", e)
|
||||||
if 's' in locals().keys():
|
if 's' in locals().keys():
|
||||||
del s
|
del s
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
# 依赖于psutil跨平台库
|
# 依赖于psutil跨平台库
|
||||||
# 版本:1.0.3, 支持Python版本:2.7 to 3.10
|
# 版本: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
|
# 支持操作系统: Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures
|
||||||
|
# ONLINE_PACKET_HISTORY_LEN, 探测间隔1200s,记录24小时在线率(72);探测时间300s,记录24小时(288);探测间隔60s,记录7天(10080)
|
||||||
# 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。
|
# 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。
|
||||||
|
|
||||||
SERVER = "127.0.0.1"
|
SERVER = "127.0.0.1"
|
||||||
@ -18,9 +19,11 @@ CM = "cm.tz.cloudcpp.com"
|
|||||||
PROBEPORT = 80
|
PROBEPORT = 80
|
||||||
PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6
|
PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6
|
||||||
PING_PACKET_HISTORY_LEN = 100
|
PING_PACKET_HISTORY_LEN = 100
|
||||||
|
ONLINE_PACKET_HISTORY_LEN = 72
|
||||||
INTERVAL = 1
|
INTERVAL = 1
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
|
import ssl
|
||||||
import time
|
import time
|
||||||
import timeit
|
import timeit
|
||||||
import os
|
import os
|
||||||
@ -29,10 +32,10 @@ import json
|
|||||||
import errno
|
import errno
|
||||||
import psutil
|
import psutil
|
||||||
import threading
|
import threading
|
||||||
try:
|
if sys.version_info.major == 3:
|
||||||
from queue import Queue # python3
|
from queue import Queue
|
||||||
except ImportError:
|
elif sys.version_info.major == 2:
|
||||||
from Queue import Queue # python2
|
from Queue import Queue
|
||||||
|
|
||||||
def get_uptime():
|
def get_uptime():
|
||||||
return int(time.time() - psutil.boot_time())
|
return int(time.time() - psutil.boot_time())
|
||||||
@ -148,6 +151,7 @@ diskIO = {
|
|||||||
'read': 0,
|
'read': 0,
|
||||||
'write': 0
|
'write': 0
|
||||||
}
|
}
|
||||||
|
monitorServer = {}
|
||||||
|
|
||||||
def _ping_thread(host, mark, port):
|
def _ping_thread(host, mark, port):
|
||||||
lostPacket = 0
|
lostPacket = 0
|
||||||
@ -303,6 +307,91 @@ def get_realtime_data():
|
|||||||
ti.daemon = True
|
ti.daemon = True
|
||||||
ti.start()
|
ti.start()
|
||||||
|
|
||||||
|
def _monitor_thread(name, host, interval, type):
|
||||||
|
lostPacket = 0
|
||||||
|
packet_queue = Queue(maxsize=ONLINE_PACKET_HISTORY_LEN)
|
||||||
|
while True:
|
||||||
|
if name not in monitorServer.keys():
|
||||||
|
break
|
||||||
|
if packet_queue.full():
|
||||||
|
if packet_queue.get() == 0:
|
||||||
|
lostPacket -= 1
|
||||||
|
try:
|
||||||
|
if type == "http":
|
||||||
|
address = host.replace("http://", "")
|
||||||
|
m = timeit.default_timer()
|
||||||
|
if PROBE_PROTOCOL_PREFER == 'ipv4':
|
||||||
|
IP = socket.getaddrinfo(address, None, socket.AF_INET)[0][4][0]
|
||||||
|
else:
|
||||||
|
IP = socket.getaddrinfo(address, None, socket.AF_INET6)[0][4][0]
|
||||||
|
monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
k = socket.create_connection((IP, 80), timeout=6)
|
||||||
|
monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
k.sendall("GET / HTTP/1.2\r\nHost:{}\r\nUser-Agent:ServerStatus/cppla\r\nConnection:close\r\n\r\n".format(address).encode('utf-8'))
|
||||||
|
response = b""
|
||||||
|
while True:
|
||||||
|
data = k.recv(4096)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
response += data
|
||||||
|
http_code = response.decode('utf-8').split('\r\n')[0].split()[1]
|
||||||
|
monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
k.close()
|
||||||
|
if http_code not in ['200', '204', '301', '302', '401']:
|
||||||
|
raise Exception("http code not in 200, 204, 301, 302, 401")
|
||||||
|
elif type == "https":
|
||||||
|
context = ssl._create_unverified_context()
|
||||||
|
address = host.replace("https://", "")
|
||||||
|
m = timeit.default_timer()
|
||||||
|
if PROBE_PROTOCOL_PREFER == 'ipv4':
|
||||||
|
IP = socket.getaddrinfo(address, None, socket.AF_INET)[0][4][0]
|
||||||
|
else:
|
||||||
|
IP = socket.getaddrinfo(address, None, socket.AF_INET6)[0][4][0]
|
||||||
|
monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
k = socket.create_connection((IP, 443), timeout=6)
|
||||||
|
monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
kk = context.wrap_socket(k, server_hostname=address)
|
||||||
|
kk.sendall("GET / HTTP/1.2\r\nHost:{}\r\nUser-Agent:ServerStatus/cppla\r\nConnection:close\r\n\r\n".format(address).encode('utf-8'))
|
||||||
|
response = b""
|
||||||
|
while True:
|
||||||
|
data = kk.recv(4096)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
response += data
|
||||||
|
http_code = response.decode('utf-8').split('\r\n')[0].split()[1]
|
||||||
|
monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
kk.close()
|
||||||
|
k.close()
|
||||||
|
if http_code not in ['200', '204', '301', '302', '401']:
|
||||||
|
raise Exception("http code not in 200, 204, 301, 302, 401")
|
||||||
|
elif type == "tcp":
|
||||||
|
m = timeit.default_timer()
|
||||||
|
if PROBE_PROTOCOL_PREFER == 'ipv4':
|
||||||
|
IP = socket.getaddrinfo(host.split(":")[0], None, socket.AF_INET)[0][4][0]
|
||||||
|
else:
|
||||||
|
IP = socket.getaddrinfo(host.split(":")[0], None, socket.AF_INET6)[0][4][0]
|
||||||
|
monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
k = socket.create_connection((IP, int(host.split(":")[1])), timeout=6)
|
||||||
|
monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
m = timeit.default_timer()
|
||||||
|
k.send(b"GET / HTTP/1.2\r\n\r\n")
|
||||||
|
k.recv(1024)
|
||||||
|
monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000)
|
||||||
|
k.close()
|
||||||
|
packet_queue.put(1)
|
||||||
|
except Exception as e:
|
||||||
|
lostPacket += 1
|
||||||
|
packet_queue.put(0)
|
||||||
|
if packet_queue.qsize() > 5:
|
||||||
|
monitorServer[name]["online_rate"] = 1 - float(lostPacket) / packet_queue.qsize()
|
||||||
|
time.sleep(interval)
|
||||||
|
|
||||||
|
|
||||||
def byte_str(object):
|
def byte_str(object):
|
||||||
'''
|
'''
|
||||||
bytes to str, str to bytes
|
bytes to str, str to bytes
|
||||||
@ -349,6 +438,27 @@ if __name__ == '__main__':
|
|||||||
if data.find("You are connecting via") < 0:
|
if data.find("You are connecting via") < 0:
|
||||||
data = byte_str(s.recv(1024))
|
data = byte_str(s.recv(1024))
|
||||||
print(data)
|
print(data)
|
||||||
|
for i in data.split('\n'):
|
||||||
|
if "monitor" in i and "type" in i and "{" in i and "}" in i:
|
||||||
|
jdata = json.loads(i[i.find("{"):i.find("}")+1])
|
||||||
|
monitorServer[jdata.get("name")] = {
|
||||||
|
"type": jdata.get("type"),
|
||||||
|
"dns_time": 0,
|
||||||
|
"connect_time": 0,
|
||||||
|
"download_time": 0,
|
||||||
|
"online_rate": 1
|
||||||
|
}
|
||||||
|
t = threading.Thread(
|
||||||
|
target=_monitor_thread,
|
||||||
|
kwargs={
|
||||||
|
'name': jdata.get("name"),
|
||||||
|
'host': jdata.get("host"),
|
||||||
|
'interval': jdata.get("interval"),
|
||||||
|
'type': jdata.get("type")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
|
||||||
timer = 0
|
timer = 0
|
||||||
check_ip = 0
|
check_ip = 0
|
||||||
@ -368,7 +478,6 @@ if __name__ == '__main__':
|
|||||||
MemoryTotal, MemoryUsed = get_memory()
|
MemoryTotal, MemoryUsed = get_memory()
|
||||||
SwapTotal, SwapUsed = get_swap()
|
SwapTotal, SwapUsed = get_swap()
|
||||||
HDDTotal, HDDUsed = get_hdd()
|
HDDTotal, HDDUsed = get_hdd()
|
||||||
|
|
||||||
array = {}
|
array = {}
|
||||||
if not timer:
|
if not timer:
|
||||||
array['online' + str(check_ip)] = get_network(check_ip)
|
array['online' + str(check_ip)] = get_network(check_ip)
|
||||||
@ -391,8 +500,6 @@ if __name__ == '__main__':
|
|||||||
array['network_tx'] = netSpeed.get("nettx")
|
array['network_tx'] = netSpeed.get("nettx")
|
||||||
array['network_in'] = NET_IN
|
array['network_in'] = NET_IN
|
||||||
array['network_out'] = NET_OUT
|
array['network_out'] = NET_OUT
|
||||||
# todo:兼容旧版本,下个版本删除ip_status
|
|
||||||
array['ip_status'] = True
|
|
||||||
array['ping_10010'] = lostRate.get('10010') * 100
|
array['ping_10010'] = lostRate.get('10010') * 100
|
||||||
array['ping_189'] = lostRate.get('189') * 100
|
array['ping_189'] = lostRate.get('189') * 100
|
||||||
array['ping_10086'] = lostRate.get('10086') * 100
|
array['ping_10086'] = lostRate.get('10086') * 100
|
||||||
@ -402,16 +509,18 @@ if __name__ == '__main__':
|
|||||||
array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
|
array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
|
||||||
array['io_read'] = diskIO.get("read")
|
array['io_read'] = diskIO.get("read")
|
||||||
array['io_write'] = diskIO.get("write")
|
array['io_write'] = diskIO.get("write")
|
||||||
|
array['custom'] = "<br>".join(f"{k}\\t解析: {v['dns_time']}\\t连接: {v['connect_time']}\\t下载: {v['download_time']}\\t在线率: <code>{v['online_rate']*100:.2f}%</code>" for k, v in monitorServer.items())
|
||||||
s.send(byte_str("update " + json.dumps(array) + "\n"))
|
s.send(byte_str("update " + json.dumps(array) + "\n"))
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
except socket.error:
|
except socket.error:
|
||||||
|
monitorServer.clear()
|
||||||
print("Disconnected...")
|
print("Disconnected...")
|
||||||
if 's' in locals().keys():
|
if 's' in locals().keys():
|
||||||
del s
|
del s
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
monitorServer.clear()
|
||||||
print("Caught Exception:", e)
|
print("Caught Exception:", e)
|
||||||
if 's' in locals().keys():
|
if 's' in locals().keys():
|
||||||
del s
|
del s
|
||||||
|
@ -5,6 +5,11 @@ services:
|
|||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
image: serverstatus_server
|
image: serverstatus_server
|
||||||
|
healthcheck:
|
||||||
|
test: curl --fail http://localhost:80 || bash -c 'kill -s 15 -1 && (sleep 10; kill -s 9 -1)'
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 5
|
||||||
container_name: serverstatus
|
container_name: serverstatus
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
@ -19,7 +24,6 @@ services:
|
|||||||
|
|
||||||
networks:
|
networks:
|
||||||
serverstatus-network:
|
serverstatus-network:
|
||||||
name: serverstatus-network
|
|
||||||
ipam:
|
ipam:
|
||||||
config:
|
config:
|
||||||
- subnet: 172.23.0.0/24
|
- subnet: 172.23.0.0/24
|
||||||
|
@ -38,6 +38,20 @@
|
|||||||
"monthstart": 1
|
"monthstart": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"monitors": [
|
||||||
|
{
|
||||||
|
"name": "baidu",
|
||||||
|
"host": "https://www.baidu.com",
|
||||||
|
"interval": 1200,
|
||||||
|
"type": "https"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1111",
|
||||||
|
"host": "1.1.1.1:80",
|
||||||
|
"interval": 1200,
|
||||||
|
"type": "tcp"
|
||||||
|
}
|
||||||
|
],
|
||||||
"watchdog": [
|
"watchdog": [
|
||||||
{
|
{
|
||||||
"name": "cpu high warning,exclude username s01",
|
"name": "cpu high warning,exclude username s01",
|
||||||
@ -52,23 +66,35 @@
|
|||||||
"callback": "https://yourSMSurl"
|
"callback": "https://yourSMSurl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "offline warning,exclude name node1",
|
"name": "offline warning",
|
||||||
"rule": "online4=0&online6=0&name!='node1'",
|
"rule": "online4=0&online6=0",
|
||||||
"interval": 600,
|
"interval": 600,
|
||||||
"callback": "https://yourSMSurl"
|
"callback": "https://yourSMSurl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ddcc attack,limit type Oracle",
|
"name": "ddcc attack,limit type Oracle",
|
||||||
"rule": "tcp_count>600&type='Oracle'",
|
"rule": "tcp_count>600&type='Oracle'",
|
||||||
"interval": 300,
|
"interval": 300,
|
||||||
"callback": "https://yourSMSurl"
|
"callback": "https://yourSMSurl"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "month traffic warning",
|
"name": "month 999GB traffic warning",
|
||||||
"rule": "(network_out-last_network_out)/1024/1024/1024>999",
|
"rule": "(network_out-last_network_out)/1024/1024/1024>999",
|
||||||
"interval": 3600,
|
"interval": 3600,
|
||||||
"callback": "https://yourSMSurl"
|
"callback": "https://yourSMSurl"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "aliyun china free 18GB traffic warning",
|
||||||
|
"rule": "(network_out-last_network_out)/1024/1024/1024>18&(username='aliyun1'|username='aliyun2')",
|
||||||
|
"interval": 3600,
|
||||||
|
"callback": "https://yourSMSurl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "packet loss rate warning",
|
||||||
|
"rule": "(ping_10010>10|ping_189>10|ping_10086>10)&(host='sgp'|host='qqhk'|host='hk-21-x'|host='hk-31-x')",
|
||||||
|
"interval": 3600,
|
||||||
|
"callback": "https://yourSMSurl"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "you can parse an expression combining any known field",
|
"name": "you can parse an expression combining any known field",
|
||||||
"rule": "load_5>3",
|
"rule": "load_5>3",
|
||||||
|
13419
server/src/exprtk.hpp
13419
server/src/exprtk.hpp
File diff suppressed because it is too large
Load Diff
@ -92,19 +92,24 @@ void CMain::OnNewClient(int ClientNetID, int ClientID)
|
|||||||
Client(ClientID)->m_Stats.m_Online4 = true;
|
Client(ClientID)->m_Stats.m_Online4 = true;
|
||||||
else if(Client(ClientID)->m_ClientNetType == NETTYPE_IPV6)
|
else if(Client(ClientID)->m_ClientNetType == NETTYPE_IPV6)
|
||||||
Client(ClientID)->m_Stats.m_Online6 = true;
|
Client(ClientID)->m_Stats.m_Online6 = true;
|
||||||
|
|
||||||
|
// Send monitor to client
|
||||||
|
// support by cpp.la
|
||||||
|
int ID = 0;
|
||||||
|
char monitorBuffer[2048];
|
||||||
|
while (strcmp(Monitors(ID)->m_aName, "NULL"))
|
||||||
|
{
|
||||||
|
memset(monitorBuffer, 0, sizeof(monitorBuffer));
|
||||||
|
sprintf(monitorBuffer, "{\"name\":\"%s\",\"host\":\"%s\",\"interval\":%d,\"type\":\"%s\",\"monitor\":%d}", Monitors(ID)->m_aName, Monitors(ID)->m_aHost, Monitors(ID)->m_aInterval, Monitors(ID)->m_aType, ID);
|
||||||
|
m_Server.Network()->Send(ClientNetID, monitorBuffer);
|
||||||
|
ID++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMain::OnDelClient(int ClientNetID)
|
void CMain::OnDelClient(int ClientNetID)
|
||||||
{
|
{
|
||||||
int ClientID = ClientNetToClient(ClientNetID);
|
int ClientID = ClientNetToClient(ClientNetID);
|
||||||
dbg_msg("main", "OnDelClient(ncid=%d, cid=%d)", ClientNetID, ClientID);
|
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)
|
if(ClientID >= 0 && ClientID < NET_MAX_CLIENTS)
|
||||||
{
|
{
|
||||||
Client(ClientID)->m_Connected = false;
|
Client(ClientID)->m_Connected = false;
|
||||||
@ -112,6 +117,10 @@ void CMain::OnDelClient(int ClientNetID)
|
|||||||
Client(ClientID)->m_ClientNetType = NETTYPE_INVALID;
|
Client(ClientID)->m_ClientNetType = NETTYPE_INVALID;
|
||||||
mem_zero(&Client(ClientID)->m_Stats, sizeof(CClient::CStats));
|
mem_zero(&Client(ClientID)->m_Stats, sizeof(CClient::CStats));
|
||||||
}
|
}
|
||||||
|
m_OfflineAlarmThreadData.pClients = m_aClients;
|
||||||
|
m_OfflineAlarmThreadData.pWatchDogs = m_aCWatchDogs;
|
||||||
|
m_OfflineAlarmThreadData.m_ReloadRequired = ClientID;
|
||||||
|
thread_create(offlineAlarmThread, &m_OfflineAlarmThreadData);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CMain::HandleMessage(int ClientNetID, char *pMessage)
|
int CMain::HandleMessage(int ClientNetID, char *pMessage)
|
||||||
@ -207,7 +216,8 @@ int CMain::HandleMessage(int ClientNetID, char *pMessage)
|
|||||||
pClient->m_Stats.m_time_10010, pClient->m_Stats.m_time_189, pClient->m_Stats.m_time_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_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_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_NetworkIN, pClient->m_Stats.m_NetworkOUT,
|
||||||
|
pClient->m_LastNetworkIN, pClient->m_LastNetworkOUT, pClient->m_Stats.m_MemTotal,
|
||||||
pClient->m_Stats.m_MemUsed, pClient->m_Stats.m_SwapTotal, pClient->m_Stats.m_SwapUsed,
|
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_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_IOWrite, pClient->m_Stats.m_CPU, pClient->m_Stats.m_Online4,
|
||||||
@ -259,13 +269,30 @@ int CMain::HandleMessage(int ClientNetID, char *pMessage)
|
|||||||
|
|
||||||
void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086,
|
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 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 network_rx, double network_tx, double network_in, double network_out, double last_network_in, double last_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 swap_total, double swap_used, double hdd_total, double hdd_used, double io_read, double io_write, double cpu,
|
||||||
double online4, double online6)
|
double online4, double online6)
|
||||||
{
|
{
|
||||||
int ID = 0;
|
int ID = 0;
|
||||||
while (strcmp(Watchdog(ID)->m_aName, "NULL"))
|
while (strcmp(Watchdog(ID)->m_aName, "NULL"))
|
||||||
{
|
{
|
||||||
|
// Exprtk库默认使用窄字符类型,但可能会出现中文等Unicode字符无法正确解析的问题。
|
||||||
|
// todo: 为解决此问题,可以使用宽字符类型替换Exprtk库中默认的窄字符类型。
|
||||||
|
// #include <string>
|
||||||
|
// #include <vector>
|
||||||
|
// #include <exprtk.hpp>
|
||||||
|
// typedef exprtk::expression<wchar_t> expression_type;
|
||||||
|
// typedef exprtk::parser<wchar_t> parser_type;
|
||||||
|
// int main()
|
||||||
|
// {
|
||||||
|
// std::wstring expression_string = L"sin(x)";
|
||||||
|
// expression_type expression;
|
||||||
|
// parser_type parser;
|
||||||
|
// parser.compile(expression_string, expression);
|
||||||
|
// double x = 3.14;
|
||||||
|
// double result = expression.value();
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
typedef exprtk::symbol_table<double> symbol_table_t;
|
typedef exprtk::symbol_table<double> symbol_table_t;
|
||||||
typedef exprtk::expression<double> expression_t;
|
typedef exprtk::expression<double> expression_t;
|
||||||
typedef exprtk::parser<double> parser_t;
|
typedef exprtk::parser<double> parser_t;
|
||||||
@ -300,6 +327,8 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl
|
|||||||
symbol_table.add_variable("network_tx",network_tx);
|
symbol_table.add_variable("network_tx",network_tx);
|
||||||
symbol_table.add_variable("network_in",network_in);
|
symbol_table.add_variable("network_in",network_in);
|
||||||
symbol_table.add_variable("network_out",network_out);
|
symbol_table.add_variable("network_out",network_out);
|
||||||
|
symbol_table.add_variable("last_network_in",last_network_in);
|
||||||
|
symbol_table.add_variable("last_network_out",last_network_out);
|
||||||
symbol_table.add_variable("memory_total",memory_total);
|
symbol_table.add_variable("memory_total",memory_total);
|
||||||
symbol_table.add_variable("memory_used",memory_used);
|
symbol_table.add_variable("memory_used",memory_used);
|
||||||
symbol_table.add_variable("swap_total",swap_total);
|
symbol_table.add_variable("swap_total",swap_total);
|
||||||
@ -324,6 +353,11 @@ void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, doubl
|
|||||||
time_t currentStamp = (long long)time(/*ago*/0);
|
time_t currentStamp = (long long)time(/*ago*/0);
|
||||||
if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > Watchdog(ID)->m_aInterval)
|
if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > Watchdog(ID)->m_aInterval)
|
||||||
{
|
{
|
||||||
|
if (!Client(ClientID)->m_Stats.m_Online4 && !Client(ClientID)->m_Stats.m_Online6)
|
||||||
|
{
|
||||||
|
//休眠5分钟如果5分钟后状态发生了变更,消息不发出。
|
||||||
|
printf("download\n");
|
||||||
|
}
|
||||||
Client(ClientID)->m_AlarmLastTime = currentStamp;
|
Client(ClientID)->m_AlarmLastTime = currentStamp;
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
CURLcode res;
|
CURLcode res;
|
||||||
@ -469,6 +503,109 @@ void CMain::JSONUpdateThread(void *pUser)
|
|||||||
fs_rename(pConfig->m_aJSONFile, aJSONFileTmp);
|
fs_rename(pConfig->m_aJSONFile, aJSONFileTmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMain::offlineAlarmThread(void *pUser)
|
||||||
|
{
|
||||||
|
CJSONUpdateThreadData *m_OfflineAlarmThreadData = (CJSONUpdateThreadData *)pUser;
|
||||||
|
CClient *pClients = m_OfflineAlarmThreadData->pClients;
|
||||||
|
CWatchDog *pWatchDogs = m_OfflineAlarmThreadData->pWatchDogs;
|
||||||
|
volatile short ClientID = m_OfflineAlarmThreadData->m_ReloadRequired;
|
||||||
|
thread_sleep(25000);
|
||||||
|
if(!pClients[ClientID].m_Connected)
|
||||||
|
{
|
||||||
|
int ID = 0;
|
||||||
|
while (strcmp(pWatchDogs[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 = pWatchDogs[ID].m_aRule;
|
||||||
|
std::string username = pClients[ClientID].m_aUsername;
|
||||||
|
std::string name = pClients[ClientID].m_aName;
|
||||||
|
std::string type = pClients[ClientID].m_aType;
|
||||||
|
std::string host = pClients[ClientID].m_aHost;
|
||||||
|
std::string location = pClients[ClientID].m_aLocation;
|
||||||
|
std::double_t online4 = pClients[ClientID].m_Stats.m_Online4;
|
||||||
|
std::double_t online6 = pClients[ClientID].m_Stats.m_Online6;
|
||||||
|
|
||||||
|
symbol_table_t symbol_table;
|
||||||
|
symbol_table.add_stringvar("username", username);
|
||||||
|
symbol_table.add_stringvar("name", name);
|
||||||
|
symbol_table.add_stringvar("type", type);
|
||||||
|
symbol_table.add_stringvar("host", host);
|
||||||
|
symbol_table.add_stringvar("location", location);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
time_t currentStamp = (long long)time(/*ago*/0);
|
||||||
|
if ((currentStamp-pClients[ClientID].m_AlarmLastTime) > pWatchDogs[ID].m_aInterval)
|
||||||
|
{
|
||||||
|
printf("客户端下线且超过阈值, Client disconnects and sends alert information\n");
|
||||||
|
pClients[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(¤tStamp));
|
||||||
|
|
||||||
|
//url encode, Rules conflict with url special characters,eg:&, 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",
|
||||||
|
pWatchDogs[ID].m_aName,
|
||||||
|
standardTime,
|
||||||
|
pClients[ClientID].m_aUsername,
|
||||||
|
pClients[ClientID].m_aName,
|
||||||
|
pClients[ClientID].m_aType,
|
||||||
|
pClients[ClientID].m_aHost,
|
||||||
|
pClients[ClientID].m_aLocation);
|
||||||
|
char *encodeUrl = curl_easy_escape(curl, encodeBuffer, strlen(encodeBuffer));
|
||||||
|
|
||||||
|
//standard url
|
||||||
|
char urlBuffer[2048] = { 0 };
|
||||||
|
sprintf(urlBuffer, "%s%s",pWatchDogs[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();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printf("客户端下线但未超过阈值,No alarm if the threshold is not exceeded\n");
|
||||||
|
}
|
||||||
|
ID++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("网络波动,No alarm information is sent due to network fluctuations\n");
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
int CMain::ReadConfig()
|
int CMain::ReadConfig()
|
||||||
{
|
{
|
||||||
// read and parse config
|
// read and parse config
|
||||||
@ -572,6 +709,28 @@ int CMain::ReadConfig()
|
|||||||
} else
|
} else
|
||||||
str_copy(Watchdog(ID)->m_aName, "NULL", sizeof(Watchdog(ID)->m_aName));
|
str_copy(Watchdog(ID)->m_aName, "NULL", sizeof(Watchdog(ID)->m_aName));
|
||||||
|
|
||||||
|
// monitor
|
||||||
|
// support by: https://cpp.la
|
||||||
|
ID = 0;
|
||||||
|
const json_value &mStart = (*pJsonData)["monitors"];
|
||||||
|
if(mStart.type == json_array)
|
||||||
|
{
|
||||||
|
for(unsigned i = 0; i < mStart.u.array.length; i++)
|
||||||
|
{
|
||||||
|
if(ID < 0 || ID >= NET_MAX_CLIENTS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
str_copy(Monitors(ID)->m_aName, mStart[i]["name"].u.string.ptr, sizeof(Monitors(ID)->m_aName));
|
||||||
|
str_copy(Monitors(ID)->m_aHost, mStart[i]["host"].u.string.ptr, sizeof(Monitors(ID)->m_aHost));
|
||||||
|
Monitors(ID)->m_aInterval = mStart[i]["interval"].u.integer;
|
||||||
|
str_copy(Monitors(ID)->m_aType, mStart[i]["type"].u.string.ptr, sizeof(Monitors(ID)->m_aType));
|
||||||
|
|
||||||
|
ID++;
|
||||||
|
}
|
||||||
|
str_copy(Monitors(ID)->m_aName, "NULL", sizeof(Monitors(ID)->m_aName));
|
||||||
|
} else
|
||||||
|
str_copy(Monitors(ID)->m_aName, "NULL", sizeof(Monitors(ID)->m_aName));
|
||||||
|
|
||||||
// if file exists, read last network traffic record,reset m_LastNetworkIN and m_LastNetworkOUT
|
// if file exists, read last network traffic record,reset m_LastNetworkIN and m_LastNetworkOUT
|
||||||
// support by: https://cpp.la
|
// support by: https://cpp.la
|
||||||
IOHANDLE nFile = io_open(m_Config.m_aJSONFile, IOFLAG_READ);
|
IOHANDLE nFile = io_open(m_Config.m_aJSONFile, IOFLAG_READ);
|
||||||
@ -645,6 +804,7 @@ int CMain::Run()
|
|||||||
m_JSONUpdateThreadData.m_ReloadRequired = 2;
|
m_JSONUpdateThreadData.m_ReloadRequired = 2;
|
||||||
m_JSONUpdateThreadData.pClients = m_aClients;
|
m_JSONUpdateThreadData.pClients = m_aClients;
|
||||||
m_JSONUpdateThreadData.pConfig = &m_Config;
|
m_JSONUpdateThreadData.pConfig = &m_Config;
|
||||||
|
m_JSONUpdateThreadData.pWatchDogs = m_aCWatchDogs;
|
||||||
void *LoadThread = thread_create(JSONUpdateThread, &m_JSONUpdateThreadData);
|
void *LoadThread = thread_create(JSONUpdateThread, &m_JSONUpdateThreadData);
|
||||||
//thread_detach(LoadThread);
|
//thread_detach(LoadThread);
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ class CMain
|
|||||||
int64_t m_IORead;
|
int64_t m_IORead;
|
||||||
int64_t m_IOWrite;
|
int64_t m_IOWrite;
|
||||||
double m_CPU;
|
double m_CPU;
|
||||||
char m_aCustom[512];
|
char m_aCustom[1024];
|
||||||
// Options
|
// Options
|
||||||
bool m_Pong;
|
bool m_Pong;
|
||||||
} m_Stats;
|
} m_Stats;
|
||||||
@ -90,14 +90,23 @@ class CMain
|
|||||||
char m_aCallback[1024];
|
char m_aCallback[1024];
|
||||||
} m_aCWatchDogs[NET_MAX_CLIENTS];
|
} m_aCWatchDogs[NET_MAX_CLIENTS];
|
||||||
|
|
||||||
|
struct CMonitors{
|
||||||
|
char m_aName[128];
|
||||||
|
char m_aHost[128];
|
||||||
|
int m_aInterval;
|
||||||
|
char m_aType[128];
|
||||||
|
} m_aCMonitors[NET_MAX_CLIENTS];
|
||||||
|
|
||||||
struct CJSONUpdateThreadData
|
struct CJSONUpdateThreadData
|
||||||
{
|
{
|
||||||
CClient *pClients;
|
CClient *pClients;
|
||||||
CConfig *pConfig;
|
CConfig *pConfig;
|
||||||
|
CWatchDog *pWatchDogs;
|
||||||
volatile short m_ReloadRequired;
|
volatile short m_ReloadRequired;
|
||||||
} m_JSONUpdateThreadData;
|
} m_JSONUpdateThreadData, m_OfflineAlarmThreadData;
|
||||||
|
|
||||||
static void JSONUpdateThread(void *pUser);
|
static void JSONUpdateThread(void *pUser);
|
||||||
|
static void offlineAlarmThread(void *pUser);
|
||||||
public:
|
public:
|
||||||
CMain(CConfig Config);
|
CMain(CConfig Config);
|
||||||
|
|
||||||
@ -108,11 +117,13 @@ public:
|
|||||||
int Run();
|
int Run();
|
||||||
|
|
||||||
CWatchDog *Watchdog(int ruleID) { return &m_aCWatchDogs[ruleID]; }
|
CWatchDog *Watchdog(int ruleID) { return &m_aCWatchDogs[ruleID]; }
|
||||||
|
CMonitors *Monitors(int ruleID) { return &m_aCMonitors[ruleID]; }
|
||||||
|
|
||||||
void WatchdogMessage(int ClientNetID,
|
void WatchdogMessage(int ClientNetID,
|
||||||
double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086,
|
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 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 network_rx, double network_tx, double network_in, double network_out, double last_network_in, double last_network_out,
|
||||||
double memory_used,double swap_total, double swap_used, double hdd_total,
|
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);
|
double hdd_used, double io_read, double io_write, double cpu,double online4, double online6);
|
||||||
|
|
||||||
CClient *Client(int ClientID) { return &m_aClients[ClientID]; }
|
CClient *Client(int ClientID) { return &m_aClients[ClientID]; }
|
||||||
|
@ -10,7 +10,7 @@ enum
|
|||||||
NET_CONNSTATE_ERROR=4,
|
NET_CONNSTATE_ERROR=4,
|
||||||
|
|
||||||
NET_MAX_PACKETSIZE = 1400,
|
NET_MAX_PACKETSIZE = 1400,
|
||||||
NET_MAX_CLIENTS = 256
|
NET_MAX_CLIENTS = 512
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*NETFUNC_DELCLIENT)(int ClientID, const char* pReason, void *pUser);
|
typedef int (*NETFUNC_DELCLIENT)(int ClientID, const char* pReason, void *pUser);
|
||||||
|
File diff suppressed because one or more lines are too long
1
web/assets/index-e069a4f0.js
Normal file
1
web/assets/index-e069a4f0.js
Normal file
File diff suppressed because one or more lines are too long
6
web/css/bootstrap-theme.min.css
vendored
6
web/css/bootstrap-theme.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
10
web/css/bootstrap.min.css
vendored
10
web/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
234
web/css/dark.css
234
web/css/dark.css
@ -1,70 +1,182 @@
|
|||||||
body { background: #212e36 url('../img/dark.png'); color: #dcdcdc; }
|
body {
|
||||||
.navbar { min-height: 40px; }
|
background: #212e36 url('../img/dark.png') repeat;
|
||||||
.navbar-brand { color: #FFF !important; padding: 10px; font-size: 20px; }
|
color: #dcdcdc;
|
||||||
.dropdown .dropdown-toggle { padding-bottom: 10px; padding-top: 10px; }
|
font-size: 15px;
|
||||||
.dropdown-menu > li > a { color: #FFF !important; background-color: #222222 !important; }
|
padding-top: 70px;
|
||||||
.dropdown-menu > li > a:hover { color: #FFF !important; background: #000 !important; }
|
padding-bottom: 30px;
|
||||||
.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; }
|
|
||||||
.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; }
|
.navbar {
|
||||||
.table { background: #363b40; margin-bottom: 0; border-collapse: collapse; border-radius: 3px; }
|
min-height: 40px;
|
||||||
.table th { text-align: center; }
|
background-color: #1B1B1B;
|
||||||
.table-striped tbody > tr.even > td, .table-striped tbody > tr.even > th { background-color: #212e36; }
|
}
|
||||||
.table-striped tbody > tr.odd > td, .table-striped tbody > tr.odd > th { background-color: #212e36; }
|
|
||||||
.table td { text-align: center; border-color: #2F2F2F; }
|
.navbar-brand {
|
||||||
.progress { margin-bottom: 0; background: #363b40; }
|
color: #FFF !important;
|
||||||
.table-hover > tbody > tr:hover > td { background: #414141; }
|
padding: 10px;
|
||||||
tr.even.expandRow > :hover { background: #212e36 !important; }
|
font-size: 20px;
|
||||||
tr.odd.expandRow > :hover { background: #212e36 !important; }
|
}
|
||||||
.expandRow > td { padding: 0 !important; border-top: 0px !important; }
|
|
||||||
#month_traffic { min-width: 85px; max-width: 95px;}
|
.dropdown .dropdown-toggle {
|
||||||
#network { min-width: 110px; }
|
padding-bottom: 10px;
|
||||||
#cpu, #ram, #hdd { min-width: 45px; max-width: 90px; }
|
padding-top: 10px;
|
||||||
#ping { max-width: 110px; }
|
}
|
||||||
|
|
||||||
|
.dropdown-menu > li > a {
|
||||||
|
color: #FFF !important;
|
||||||
|
background-color: #222222 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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: linear-gradient(to bottom, #212e36, #212e36);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
border-color: #252525;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background: #212e36;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #212e36;
|
||||||
|
box-shadow: 0 0px 0px rgba(0, 0, 0, 0);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
background-color: #212e36 !important;
|
||||||
|
margin-bottom: 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-radius: 3px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th, .table td {
|
||||||
|
background-color: #212e36 !important;
|
||||||
|
color: #dcdcdc !important;
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-striped tbody tr:nth-child(even) {
|
||||||
|
background-color: #212e36;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-striped tbody tr:nth-child(odd) {
|
||||||
|
background-color: #212e36;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
margin-bottom: 0;
|
||||||
|
background: #363b40;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-hover tbody tr:hover td {
|
||||||
|
background: #414141;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.even.expandRow:hover {
|
||||||
|
background: #212e36 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.odd.expandRow:hover {
|
||||||
|
background: #212e36 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expandRow td {
|
||||||
|
padding: 0 !important;
|
||||||
|
border-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#month_traffic {
|
||||||
|
min-width: 85px;
|
||||||
|
max-width: 95px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#traffic, #network {
|
||||||
|
width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpu, #ram, #hdd {
|
||||||
|
min-width: 45px;
|
||||||
|
max-width: 68px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ping {
|
||||||
|
width: 115px;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 1200px) {
|
@media only screen and (max-width: 1200px) {
|
||||||
#type, tr td:nth-child(4) { display:none; visibility:hidden; }
|
body {
|
||||||
#location, tr td:nth-child(5) { display:none; visibility:hidden; }
|
font-size: 10px;
|
||||||
#uptime, tr td:nth-child(6) { display:none; visibility:hidden; }
|
}
|
||||||
#ping, tr td:nth-child(13) { display:none; visibility:hidden; }
|
|
||||||
|
.content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#traffic, #network {
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
#type, #location, #uptime, #ping {
|
||||||
|
display: none;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 720px) {
|
@media only screen and (max-width: 720px) {
|
||||||
body { font-size: 10px; }
|
body {
|
||||||
.content { padding: 0; }
|
font-size: 10px;
|
||||||
#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; }
|
.content {
|
||||||
#ping, tr td:nth-child(13) { display:none; visibility:hidden; }
|
padding: 0;
|
||||||
|
}
|
||||||
|
#traffic, #network {
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
#month_traffic, #type, #location, #uptime, #ping {
|
||||||
|
display: none;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 620px) {
|
@media only screen and (max-width: 620px) {
|
||||||
body { font-size: 10px; }
|
body {
|
||||||
.content { padding: 0; }
|
font-size: 10px;
|
||||||
#month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; }
|
}
|
||||||
#type, tr td:nth-child(4) { display:none; visibility:hidden; }
|
|
||||||
#location, tr td:nth-child(5) { display:none; visibility:hidden; }
|
.content {
|
||||||
#uptime, tr td:nth-child(6) { display:none; visibility:hidden; }
|
padding: 0;
|
||||||
#traffic, tr td:nth-child(9) { display:none; visibility:hidden; }
|
}
|
||||||
#ping, tr td:nth-child(13) { display:none; visibility:hidden; }
|
#network {
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
#month_traffic, #type, #location, #uptime, #traffic, #ping {
|
||||||
|
display: none;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 533px) {
|
|
||||||
body { font-size: 10px; }
|
.navbar-nav .nav-link {
|
||||||
.content { padding: 0; }
|
padding-top: 0.5rem;
|
||||||
#month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; }
|
padding-bottom: 0.5rem;
|
||||||
#type, tr td:nth-child(4) { display:none; visibility:hidden; }
|
line-height: 1.5;
|
||||||
#location, tr td:nth-child(5) { display:none; visibility:hidden; }
|
|
||||||
#uptime, tr td:nth-child(6) { display:none; visibility:hidden; }
|
|
||||||
#traffic, tr td:nth-child(9) { display:none; visibility:hidden; }
|
|
||||||
#ping, tr td:nth-child(13) { display:none; visibility:hidden; }
|
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 450px) {
|
|
||||||
body { font-size: 10px; }
|
.navbar-nav .dropdown-toggle::after {
|
||||||
.content { padding: 0; }
|
vertical-align: 0.15em;
|
||||||
#month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; }
|
|
||||||
#name, tr td:nth-child(3) { min-width: 55px; max-width: 85px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; }
|
|
||||||
#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; }
|
|
||||||
#traffic, tr td:nth-child(9) { display:none; visibility:hidden; }
|
|
||||||
#cpu, #ram, #hdd { min-width: 25px; max-width: 50px; }
|
|
||||||
#ping, tr td:nth-child(13) { display:none; visibility:hidden; }
|
|
||||||
}
|
}
|
||||||
|
@ -1,67 +1,163 @@
|
|||||||
body { background: #ebebeb url('../img/light.png'); }
|
body {
|
||||||
.navbar { min-height: 40px; }
|
background: #ebebeb url('../img/light.png') repeat;
|
||||||
.navbar-brand { color: #fff; padding: 10px; font-size: 20px; }
|
font-size: 15px;
|
||||||
.dropdown .dropdown-toggle { padding-bottom: 10px; padding-top: 10px; }
|
padding-top: 70px;
|
||||||
.navbar-inverse .navbar-brand { color: #fff; padding: 10px; font-size: 20px; }
|
padding-bottom: 30px;
|
||||||
.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; }
|
.navbar {
|
||||||
.table-striped tbody > tr.even > td, .table-striped tbody > tr.even > th { background-color: #F9F9F9; }
|
min-height: 40px;
|
||||||
.table-striped tbody > tr.odd > td, .table-striped tbody > tr.odd > th { background-color: #FFF; }
|
background-color: #333;
|
||||||
.progress { margin-bottom: 0; }
|
}
|
||||||
.progress-bar { color: #000; }
|
|
||||||
.table-hover > tbody > tr:hover > td { background: #E6E6E6; }
|
.navbar-brand {
|
||||||
tr.even.expandRow > :hover { background: #F9F9F9 !important; }
|
color: #fff;
|
||||||
tr.odd.expandRow > :hover { background: #FFF !important; }
|
padding: 10px;
|
||||||
.expandRow > td { padding: 0 !important; border-top: 0px !important; }
|
font-size: 20px;
|
||||||
#month_traffic { min-width: 85px; max-width: 95px;}
|
}
|
||||||
#network { min-width: 110px; }
|
|
||||||
#cpu, #ram, #hdd { min-width: 45px; max-width: 90px; }
|
.dropdown .dropdown-toggle {
|
||||||
#ping { max-width: 110px; }
|
padding-bottom: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-inverse .navbar-brand {
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #cecece;
|
||||||
|
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;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th, .table td {
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-striped tbody tr:nth-child(even) {
|
||||||
|
background-color: #F9F9F9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-striped tbody tr:nth-child(odd) {
|
||||||
|
background-color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
color: #000;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-hover tbody tr:hover td {
|
||||||
|
background: #E6E6E6;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.even.expandRow:hover {
|
||||||
|
background: #F9F9F9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.odd.expandRow:hover {
|
||||||
|
background: #FFF !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expandRow td {
|
||||||
|
padding: 0 !important;
|
||||||
|
border-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#month_traffic {
|
||||||
|
min-width: 85px;
|
||||||
|
max-width: 95px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#traffic, #network {
|
||||||
|
width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpu, #ram, #hdd {
|
||||||
|
min-width: 45px;
|
||||||
|
max-width: 68px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ping {
|
||||||
|
width: 115px;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 1200px) {
|
@media only screen and (max-width: 1200px) {
|
||||||
#type, tr td:nth-child(4) { display:none; visibility:hidden; }
|
body {
|
||||||
#location, tr td:nth-child(5) { display:none; visibility:hidden; }
|
font-size: 10px;
|
||||||
#uptime, tr td:nth-child(6) { display:none; visibility:hidden; }
|
}
|
||||||
#ping, tr td:nth-child(13) { display:none; visibility:hidden; }
|
|
||||||
|
.content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#traffic, #network {
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
#type, #location, #uptime, #ping {
|
||||||
|
display: none;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 720px) {
|
@media only screen and (max-width: 720px) {
|
||||||
body { font-size: 10px; }
|
body {
|
||||||
.content { padding: 0; }
|
font-size: 10px;
|
||||||
#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; }
|
.content {
|
||||||
#ping, tr td:nth-child(13) { display:none; visibility:hidden; }
|
padding: 0;
|
||||||
|
}
|
||||||
|
#traffic, #network {
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
#month_traffic, #type, #location, #uptime, #ping {
|
||||||
|
display: none;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 620px) {
|
@media only screen and (max-width: 620px) {
|
||||||
body { font-size: 10px; }
|
body {
|
||||||
.content { padding: 0; }
|
font-size: 10px;
|
||||||
#month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; }
|
}
|
||||||
#type, tr td:nth-child(4) { display:none; visibility:hidden; }
|
|
||||||
#location, tr td:nth-child(5) { display:none; visibility:hidden; }
|
.content {
|
||||||
#uptime, tr td:nth-child(6) { display:none; visibility:hidden; }
|
padding: 0;
|
||||||
#traffic, tr td:nth-child(9) { display:none; visibility:hidden; }
|
}
|
||||||
#ping, tr td:nth-child(13) { display:none; visibility:hidden; }
|
#network {
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
#month_traffic, #type, #location, #uptime, #traffic, #ping {
|
||||||
|
display: none;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 533px) {
|
|
||||||
body { font-size: 10px; }
|
.navbar-nav .nav-link {
|
||||||
.content { padding: 0; }
|
padding-top: 0.5rem;
|
||||||
#month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; }
|
padding-bottom: 0.5rem;
|
||||||
#type, tr td:nth-child(4) { display:none; visibility:hidden; }
|
line-height: 1.5;
|
||||||
#location, tr td:nth-child(5) { display:none; visibility:hidden; }
|
|
||||||
#uptime, tr td:nth-child(6) { display:none; visibility:hidden; }
|
|
||||||
#traffic, tr td:nth-child(9) { display:none; visibility:hidden; }
|
|
||||||
#ping, tr td:nth-child(13) { display:none; visibility:hidden; }
|
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 450px) {
|
|
||||||
body { font-size: 10px; }
|
.navbar-nav .dropdown-toggle::after {
|
||||||
.content { padding: 0; }
|
vertical-align: 0.15em;
|
||||||
#month_traffic, tr td:nth-child(2) { display:none; visibility:hidden; }
|
|
||||||
#name, tr td:nth-child(3) { min-width: 55px; max-width: 85px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; }
|
|
||||||
#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; }
|
|
||||||
#traffic, tr td:nth-child(9) { display:none; visibility:hidden; }
|
|
||||||
#cpu, #ram, #hdd { min-width: 25px; max-width: 50px; }
|
|
||||||
#ping, tr td:nth-child(13) { display:none; visibility:hidden; }
|
|
||||||
}
|
}
|
||||||
|
216
web/index.html
216
web/index.html
@ -1,111 +1,111 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<!--
|
<html lang="zh-CN">
|
||||||
json字段保持完整, 自行自定义前端展示
|
<head>
|
||||||
ლ(•̀ _ •́ ლ)
|
<meta charset="utf-8">
|
||||||
ლ(•̀ _ •́ ლ)ლ(•̀ _ •́ ლ)
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
ლ(•̀ _ •́ ლ)ლ(•̀ _ •́ ლ)ლ(•̀ _ •́ ლ)
|
<meta name="description" content="云监控,ServerStatus中文版,ServerStatus,ServerStatus cppla">
|
||||||
ლ(•̀ _ •́ ლ)ლ(•̀ _ •́ ლ)
|
<meta name="author" content="ServerStatus Theme by AI">
|
||||||
ლ(•̀ _ •́ ლ)
|
<title>云监控</title>
|
||||||
follow me, better solution for you. by:https://cpp.la
|
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||||
-->
|
<link rel="stylesheet" href="css/light.css" title="light">
|
||||||
<html>
|
<link rel="stylesheet" href="css/dark.css" title="dark">
|
||||||
<head>
|
</head>
|
||||||
<title>云监控</title>
|
<body>
|
||||||
<meta charset="utf-8">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" role="navigation">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<div class="container">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<a class="navbar-brand" href="#">云监控</a>
|
||||||
<meta name="description" content="云监控">
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<meta name="author" content="BotoX">
|
<span class="navbar-toggler-icon"></span>
|
||||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
</button>
|
||||||
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<link rel="stylesheet" href="css/light.css" title="light">
|
<ul class="navbar-nav">
|
||||||
<link rel="stylesheet" href="css/dark.css" title="dark">
|
<li class="nav-item">
|
||||||
<style>
|
<a class="nav-link" href="#server" data-bs-toggle="tab">首页</a>
|
||||||
body {
|
</li>
|
||||||
padding-top: 70px;
|
<li class="nav-item">
|
||||||
padding-bottom: 30px;
|
<a class="nav-link" href="#monitor" data-bs-toggle="tab">服务</a>
|
||||||
}
|
</li>
|
||||||
</style>
|
<li class="nav-item dropdown">
|
||||||
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<!--[if lt IE 9]>
|
风格
|
||||||
<script src="js/html5shiv.js"></script>
|
</a>
|
||||||
<script src="js/respond.min.js"></script>
|
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||||
<![endif]-->
|
<li><a class="dropdown-item" href="#" onclick="setActiveStyleSheet('dark')">黑夜</a></li>
|
||||||
</head>
|
<li><a class="dropdown-item" href="#" onclick="setActiveStyleSheet('light')">白天</a></li>
|
||||||
<body>
|
<li><a class="dropdown-item" href="/index3.html">简洁</a></li>
|
||||||
<div role="navigation" class="navbar navbar-inverse navbar-fixed-top">
|
</ul>
|
||||||
<div class="navbar-inner">
|
</li>
|
||||||
<div class="container">
|
</ul>
|
||||||
<div class="navbar-header">
|
</div>
|
||||||
<button data-target=".navbar-collapse" data-toggle="collapse" class="navbar-toggle" type="button">
|
</div>
|
||||||
<span class="sr-only">Toggle navigation</span>
|
</nav>
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
<a href="#" class="navbar-brand">云监控</a>
|
|
||||||
</div>
|
|
||||||
<div class="navbar-collapse collapse">
|
|
||||||
<ul class="nav navbar-nav">
|
|
||||||
<li class="dropdown">
|
|
||||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">风格<b class="caret"></b></a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a href="#" onclick="setActiveStyleSheet('dark', true)">黑夜</a></li>
|
|
||||||
<li><a href="#" onclick="setActiveStyleSheet('light', true)">白天</a></li>
|
|
||||||
<li><a href="/index3.html">简洁</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div><!--/.nav-collapse -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container content">
|
<div class="container content">
|
||||||
<div id="loading-notice">
|
<noscript>
|
||||||
<noscript>
|
<div class="alert alert-danger text-center">
|
||||||
<div class="alert alert-danger" style="text-align: center;">
|
<strong>请启用 JavaScript</strong>,否则无法正常使用本站功能。
|
||||||
<strong>Enable JavaScript</strong> , please do it.
|
</div>
|
||||||
</div>
|
</noscript>
|
||||||
</noscript>
|
<div id="loading-notice" class="text-center">
|
||||||
<div style="text-align: center;">
|
警告:如果出现此消息,请确保您已启用 Javascript!<br>
|
||||||
警告:如果出现此消息,请确保您已启用Javascript! <br />否则云监控主服务没启动或已关闭.
|
否则云监控主服务没启动或已关闭。
|
||||||
</div>
|
</div>
|
||||||
<p></p>
|
|
||||||
</div>
|
|
||||||
<table class="table table-striped table-condensed table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th id="online_status" style="text-align: center;">🔗协议</th>
|
|
||||||
<th id="month_traffic" style="text-align: center;">📊月流量↓|↑</th>
|
|
||||||
<th id="name">📌节点</th>
|
|
||||||
<th id="type">🗂️虚拟化</th>
|
|
||||||
<th id="location">🌍位置</th>
|
|
||||||
<th id="uptime">⏱️在线</th>
|
|
||||||
<th id="load">负载</th>
|
|
||||||
<th id="network">🚦网络↓|↑</th>
|
|
||||||
<th id="traffic">📋总流量↓|↑</th>
|
|
||||||
<th id="cpu">🎯核芯</th>
|
|
||||||
<th id="ram">⚡️内存</th>
|
|
||||||
<th id="hdd">💾硬盘</th>
|
|
||||||
<th id="ping">🌐CU|CT|CM</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="servers">
|
|
||||||
<!-- Servers here \o/ -->
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<br />
|
|
||||||
<div id="updated">Updating...</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container">
|
<div class="tab-content">
|
||||||
<p style="text-align: center; font-size: 10px;">
|
<div class="tab-pane fade show active" id="server">
|
||||||
<a href="https://github.com/cppla/ServerStatus">ServerStatus中文版</a>
|
<!--主机-->
|
||||||
</p>
|
<table class="table table-striped table-hover">
|
||||||
</div>
|
<thead>
|
||||||
<script src="js/jquery.min.js"></script>
|
<tr>
|
||||||
<script src="js/bootstrap.min.js"></script>
|
<th id="online_status" style="text-align: center;">🔗协议</th>
|
||||||
<script src="js/serverstatus.js"></script>
|
<th id="month_traffic" style="text-align: center;">📊月流量↓|↑</th>
|
||||||
</body>
|
<th id="name">📌节点</th>
|
||||||
</html>
|
<th id="type">🗂️虚拟化</th>
|
||||||
|
<th id="location">🌍位置</th>
|
||||||
|
<th id="uptime">⏱️在线</th>
|
||||||
|
<th id="load">负载</th>
|
||||||
|
<th id="network">🚦网络↓|↑</th>
|
||||||
|
<th id="traffic">📋总流量↓|↑</th>
|
||||||
|
<th id="cpu">🎯核芯</th>
|
||||||
|
<th id="ram">⚡️内存</th>
|
||||||
|
<th id="hdd">💾硬盘</th>
|
||||||
|
<th id="ping">🌐CU|CT|CM</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="servers">
|
||||||
|
<!-- Servers here \o/ -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane fade" id="monitor">
|
||||||
|
<!--服务-->
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th id="monitor_status" style="text-align: center;">🔗协议</th>
|
||||||
|
<th id="monitor_node">📌监测节点</th>
|
||||||
|
<th id="monitor_location">🌍监测位置</th>
|
||||||
|
<th id="monitor_text" style="text-align: center;">📋监测内容</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="monitors">
|
||||||
|
<!-- Monitors here \o/ -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<div id="updated">更新中...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="container">
|
||||||
|
<p class="text-center" style="font-size: 10px;">
|
||||||
|
<a href="https://github.com/cppla/ServerStatus">ServerStatus中文版</a>
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="js/serverstatus.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>ServerStatus</title>
|
<title>ServerStatus</title>
|
||||||
<link rel="shortcut icon" href="./assets/favicon-65bd9f8a.png" type="image/x-icon">
|
<link rel="shortcut icon" href="./assets/favicon-65bd9f8a.png" type="image/x-icon">
|
||||||
<script type="module" crossorigin src="./assets/index-982ea826.js"></script>
|
<script type="module" crossorigin src="./assets/index-e069a4f0.js"></script>
|
||||||
<link rel="stylesheet" href="./assets/index-282247e3.css">
|
<link rel="stylesheet" href="./assets/index-282247e3.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -17,8 +17,8 @@
|
|||||||
</h1>
|
</h1>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<div class="text-center absolute left-0 bottom-0 py-4 w-full">
|
<div class="text-center absolute left-0 bottom-0 py-4 w-full">
|
||||||
Powered by <a class="text-blue-500" href="https://github.com/zdz/ServerStatus-Rust"
|
Powered by <a class="text-blue-500" href="https://github.com/cppla/ServerStatus"
|
||||||
target="_blank">ServerStatus-Rust</a>.
|
target="_blank">ServerStatus中文版</a>.
|
||||||
Theme <a class="text-blue-500" href="https://github.com/orilights/ServerStatus-Theme-Light"
|
Theme <a class="text-blue-500" href="https://github.com/orilights/ServerStatus-Theme-Light"
|
||||||
target="_blank">Light</a> by <a class="text-blue-500" href="https://orilight.top/" target="_blank">OriLight</a>
|
target="_blank">Light</a> by <a class="text-blue-500" href="https://orilight.top/" target="_blank">OriLight</a>
|
||||||
</div>
|
</div>
|
||||||
|
7
web/js/bootstrap.bundle.min.js
vendored
Normal file
7
web/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
web/js/bootstrap.min.js
vendored
7
web/js/bootstrap.min.js
vendored
File diff suppressed because one or more lines are too long
326
web/js/html5shiv.js
vendored
326
web/js/html5shiv.js
vendored
@ -1,326 +0,0 @@
|
|||||||
/**
|
|
||||||
* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
|
||||||
*/
|
|
||||||
;(function(window, document) {
|
|
||||||
/*jshint evil:true */
|
|
||||||
/** version */
|
|
||||||
var version = '3.7.3';
|
|
||||||
|
|
||||||
/** Preset options */
|
|
||||||
var options = window.html5 || {};
|
|
||||||
|
|
||||||
/** Used to skip problem elements */
|
|
||||||
var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
|
|
||||||
|
|
||||||
/** Not all elements can be cloned in IE **/
|
|
||||||
var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
|
|
||||||
|
|
||||||
/** Detect whether the browser supports default html5 styles */
|
|
||||||
var supportsHtml5Styles;
|
|
||||||
|
|
||||||
/** Name of the expando, to work with multiple documents or to re-shiv one document */
|
|
||||||
var expando = '_html5shiv';
|
|
||||||
|
|
||||||
/** The id for the the documents expando */
|
|
||||||
var expanID = 0;
|
|
||||||
|
|
||||||
/** Cached data for each document */
|
|
||||||
var expandoData = {};
|
|
||||||
|
|
||||||
/** Detect whether the browser supports unknown elements */
|
|
||||||
var supportsUnknownElements;
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
try {
|
|
||||||
var a = document.createElement('a');
|
|
||||||
a.innerHTML = '<xyz></xyz>';
|
|
||||||
//if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
|
|
||||||
supportsHtml5Styles = ('hidden' in a);
|
|
||||||
|
|
||||||
supportsUnknownElements = a.childNodes.length == 1 || (function() {
|
|
||||||
// assign a false positive if unable to shiv
|
|
||||||
(document.createElement)('a');
|
|
||||||
var frag = document.createDocumentFragment();
|
|
||||||
return (
|
|
||||||
typeof frag.cloneNode == 'undefined' ||
|
|
||||||
typeof frag.createDocumentFragment == 'undefined' ||
|
|
||||||
typeof frag.createElement == 'undefined'
|
|
||||||
);
|
|
||||||
}());
|
|
||||||
} catch(e) {
|
|
||||||
// assign a false positive if detection fails => unable to shiv
|
|
||||||
supportsHtml5Styles = true;
|
|
||||||
supportsUnknownElements = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}());
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a style sheet with the given CSS text and adds it to the document.
|
|
||||||
* @private
|
|
||||||
* @param {Document} ownerDocument The document.
|
|
||||||
* @param {String} cssText The CSS text.
|
|
||||||
* @returns {StyleSheet} The style element.
|
|
||||||
*/
|
|
||||||
function addStyleSheet(ownerDocument, cssText) {
|
|
||||||
var p = ownerDocument.createElement('p'),
|
|
||||||
parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
|
|
||||||
|
|
||||||
p.innerHTML = 'x<style>' + cssText + '</style>';
|
|
||||||
return parent.insertBefore(p.lastChild, parent.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of `html5.elements` as an array.
|
|
||||||
* @private
|
|
||||||
* @returns {Array} An array of shived element node names.
|
|
||||||
*/
|
|
||||||
function getElements() {
|
|
||||||
var elements = html5.elements;
|
|
||||||
return typeof elements == 'string' ? elements.split(' ') : elements;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extends the built-in list of html5 elements
|
|
||||||
* @memberOf html5
|
|
||||||
* @param {String|Array} newElements whitespace separated list or array of new element names to shiv
|
|
||||||
* @param {Document} ownerDocument The context document.
|
|
||||||
*/
|
|
||||||
function addElements(newElements, ownerDocument) {
|
|
||||||
var elements = html5.elements;
|
|
||||||
if(typeof elements != 'string'){
|
|
||||||
elements = elements.join(' ');
|
|
||||||
}
|
|
||||||
if(typeof newElements != 'string'){
|
|
||||||
newElements = newElements.join(' ');
|
|
||||||
}
|
|
||||||
html5.elements = elements +' '+ newElements;
|
|
||||||
shivDocument(ownerDocument);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the data associated to the given document
|
|
||||||
* @private
|
|
||||||
* @param {Document} ownerDocument The document.
|
|
||||||
* @returns {Object} An object of data.
|
|
||||||
*/
|
|
||||||
function getExpandoData(ownerDocument) {
|
|
||||||
var data = expandoData[ownerDocument[expando]];
|
|
||||||
if (!data) {
|
|
||||||
data = {};
|
|
||||||
expanID++;
|
|
||||||
ownerDocument[expando] = expanID;
|
|
||||||
expandoData[expanID] = data;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns a shived element for the given nodeName and document
|
|
||||||
* @memberOf html5
|
|
||||||
* @param {String} nodeName name of the element
|
|
||||||
* @param {Document|DocumentFragment} ownerDocument The context document.
|
|
||||||
* @returns {Object} The shived element.
|
|
||||||
*/
|
|
||||||
function createElement(nodeName, ownerDocument, data){
|
|
||||||
if (!ownerDocument) {
|
|
||||||
ownerDocument = document;
|
|
||||||
}
|
|
||||||
if(supportsUnknownElements){
|
|
||||||
return ownerDocument.createElement(nodeName);
|
|
||||||
}
|
|
||||||
if (!data) {
|
|
||||||
data = getExpandoData(ownerDocument);
|
|
||||||
}
|
|
||||||
var node;
|
|
||||||
|
|
||||||
if (data.cache[nodeName]) {
|
|
||||||
node = data.cache[nodeName].cloneNode();
|
|
||||||
} else if (saveClones.test(nodeName)) {
|
|
||||||
node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
|
|
||||||
} else {
|
|
||||||
node = data.createElem(nodeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid adding some elements to fragments in IE < 9 because
|
|
||||||
// * Attributes like `name` or `type` cannot be set/changed once an element
|
|
||||||
// is inserted into a document/fragment
|
|
||||||
// * Link elements with `src` attributes that are inaccessible, as with
|
|
||||||
// a 403 response, will cause the tab/window to crash
|
|
||||||
// * Script elements appended to fragments will execute when their `src`
|
|
||||||
// or `text` property is set
|
|
||||||
return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns a shived DocumentFragment for the given document
|
|
||||||
* @memberOf html5
|
|
||||||
* @param {Document} ownerDocument The context document.
|
|
||||||
* @returns {Object} The shived DocumentFragment.
|
|
||||||
*/
|
|
||||||
function createDocumentFragment(ownerDocument, data){
|
|
||||||
if (!ownerDocument) {
|
|
||||||
ownerDocument = document;
|
|
||||||
}
|
|
||||||
if(supportsUnknownElements){
|
|
||||||
return ownerDocument.createDocumentFragment();
|
|
||||||
}
|
|
||||||
data = data || getExpandoData(ownerDocument);
|
|
||||||
var clone = data.frag.cloneNode(),
|
|
||||||
i = 0,
|
|
||||||
elems = getElements(),
|
|
||||||
l = elems.length;
|
|
||||||
for(;i<l;i++){
|
|
||||||
clone.createElement(elems[i]);
|
|
||||||
}
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shivs the `createElement` and `createDocumentFragment` methods of the document.
|
|
||||||
* @private
|
|
||||||
* @param {Document|DocumentFragment} ownerDocument The document.
|
|
||||||
* @param {Object} data of the document.
|
|
||||||
*/
|
|
||||||
function shivMethods(ownerDocument, data) {
|
|
||||||
if (!data.cache) {
|
|
||||||
data.cache = {};
|
|
||||||
data.createElem = ownerDocument.createElement;
|
|
||||||
data.createFrag = ownerDocument.createDocumentFragment;
|
|
||||||
data.frag = data.createFrag();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ownerDocument.createElement = function(nodeName) {
|
|
||||||
//abort shiv
|
|
||||||
if (!html5.shivMethods) {
|
|
||||||
return data.createElem(nodeName);
|
|
||||||
}
|
|
||||||
return createElement(nodeName, ownerDocument, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
|
|
||||||
'var n=f.cloneNode(),c=n.createElement;' +
|
|
||||||
'h.shivMethods&&(' +
|
|
||||||
// unroll the `createElement` calls
|
|
||||||
getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
|
|
||||||
data.createElem(nodeName);
|
|
||||||
data.frag.createElement(nodeName);
|
|
||||||
return 'c("' + nodeName + '")';
|
|
||||||
}) +
|
|
||||||
');return n}'
|
|
||||||
)(html5, data.frag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shivs the given document.
|
|
||||||
* @memberOf html5
|
|
||||||
* @param {Document} ownerDocument The document to shiv.
|
|
||||||
* @returns {Document} The shived document.
|
|
||||||
*/
|
|
||||||
function shivDocument(ownerDocument) {
|
|
||||||
if (!ownerDocument) {
|
|
||||||
ownerDocument = document;
|
|
||||||
}
|
|
||||||
var data = getExpandoData(ownerDocument);
|
|
||||||
|
|
||||||
if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
|
|
||||||
data.hasCSS = !!addStyleSheet(ownerDocument,
|
|
||||||
// corrects block display not defined in IE6/7/8/9
|
|
||||||
'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
|
|
||||||
// adds styling not present in IE6/7/8/9
|
|
||||||
'mark{background:#FF0;color:#000}' +
|
|
||||||
// hides non-rendered elements
|
|
||||||
'template{display:none}'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!supportsUnknownElements) {
|
|
||||||
shivMethods(ownerDocument, data);
|
|
||||||
}
|
|
||||||
return ownerDocument;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `html5` object is exposed so that more elements can be shived and
|
|
||||||
* existing shiving can be detected on iframes.
|
|
||||||
* @type Object
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* // options can be changed before the script is included
|
|
||||||
* html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
|
|
||||||
*/
|
|
||||||
var html5 = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array or space separated string of node names of the elements to shiv.
|
|
||||||
* @memberOf html5
|
|
||||||
* @type Array|String
|
|
||||||
*/
|
|
||||||
'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* current version of html5shiv
|
|
||||||
*/
|
|
||||||
'version': version,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flag to indicate that the HTML5 style sheet should be inserted.
|
|
||||||
* @memberOf html5
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
'shivCSS': (options.shivCSS !== false),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is equal to true if a browser supports creating unknown/HTML5 elements
|
|
||||||
* @memberOf html5
|
|
||||||
* @type boolean
|
|
||||||
*/
|
|
||||||
'supportsUnknownElements': supportsUnknownElements,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flag to indicate that the document's `createElement` and `createDocumentFragment`
|
|
||||||
* methods should be overwritten.
|
|
||||||
* @memberOf html5
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
'shivMethods': (options.shivMethods !== false),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A string to describe the type of `html5` object ("default" or "default print").
|
|
||||||
* @memberOf html5
|
|
||||||
* @type String
|
|
||||||
*/
|
|
||||||
'type': 'default',
|
|
||||||
|
|
||||||
// shivs the document according to the specified `html5` object options
|
|
||||||
'shivDocument': shivDocument,
|
|
||||||
|
|
||||||
//creates a shived element
|
|
||||||
createElement: createElement,
|
|
||||||
|
|
||||||
//creates a shived documentFragment
|
|
||||||
createDocumentFragment: createDocumentFragment,
|
|
||||||
|
|
||||||
//extends list of elements
|
|
||||||
addElements: addElements
|
|
||||||
};
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
// expose html5
|
|
||||||
window.html5 = html5;
|
|
||||||
|
|
||||||
// shiv the document
|
|
||||||
shivDocument(document);
|
|
||||||
|
|
||||||
if(typeof module == 'object' && module.exports){
|
|
||||||
module.exports = html5;
|
|
||||||
}
|
|
||||||
|
|
||||||
}(typeof window !== "undefined" ? window : this, document));
|
|
2
web/js/jquery.min.js
vendored
2
web/js/jquery.min.js
vendored
File diff suppressed because one or more lines are too long
5
web/js/respond.min.js
vendored
5
web/js/respond.min.js
vendored
@ -1,5 +0,0 @@
|
|||||||
/*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl
|
|
||||||
* Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT
|
|
||||||
* */
|
|
||||||
|
|
||||||
!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b<s.length;b++){var c=s[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!o[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(v(c.styleSheet.rawCssText,e,f),o[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!r||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}w()};x(),c.update=x,c.getEmValue=t,a.addEventListener?a.addEventListener("resize",b,!1):a.attachEvent&&a.attachEvent("onresize",b)}}(this);
|
|
@ -4,396 +4,350 @@ var d = 0;
|
|||||||
var server_status = new Array();
|
var server_status = new Array();
|
||||||
|
|
||||||
function timeSince(date) {
|
function timeSince(date) {
|
||||||
if(date == 0)
|
if (date == 0) return "从未.";
|
||||||
return "从未.";
|
var seconds = Math.floor((new Date() - date) / 1000);
|
||||||
|
var interval = Math.floor(seconds / 60);
|
||||||
var seconds = Math.floor((new Date() - date) / 1000);
|
return interval > 1 ? interval + " 分钟前." : "几秒前.";
|
||||||
var interval = Math.floor(seconds / 60);
|
|
||||||
if (interval > 1)
|
|
||||||
return interval + " 分钟前.";
|
|
||||||
else
|
|
||||||
return "几秒前.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function bytesToSize(bytes, precision, si)
|
function bytesToSize(bytes, precision, si = false) {
|
||||||
{
|
const units = si ? ['B', 'KB', 'MB', 'GB', 'TB'] : ['B', 'KiB', 'MiB', 'GiB', 'TiB'];
|
||||||
var ret;
|
if (bytes === 0) return '0 B';
|
||||||
si = typeof si !== 'undefined' ? si : 0;
|
const k = si ? 1000 : 1024;
|
||||||
if(si != 0) {
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
var megabyte = 1000 * 1000;
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(precision)) + ' ' + units[i];
|
||||||
var gigabyte = megabyte * 1000;
|
|
||||||
var terabyte = gigabyte * 1000;
|
|
||||||
} else {
|
|
||||||
var megabyte = 1024 * 1024;
|
|
||||||
var gigabyte = megabyte * 1024;
|
|
||||||
var terabyte = gigabyte * 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((bytes >= megabyte) && (bytes < gigabyte)) {
|
|
||||||
ret = (bytes / megabyte).toFixed(precision) + ' M';
|
|
||||||
|
|
||||||
} else if ((bytes >= gigabyte) && (bytes < terabyte)) {
|
|
||||||
ret = (bytes / gigabyte).toFixed(precision) + ' G';
|
|
||||||
|
|
||||||
} else if (bytes >= terabyte) {
|
|
||||||
ret = (bytes / terabyte).toFixed(precision) + ' T';
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return bytes + ' B';
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
/*if(si != 0) {
|
|
||||||
return ret + 'B';
|
|
||||||
} else {
|
|
||||||
return ret + 'iB';
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function uptime() {
|
function uptime() {
|
||||||
$.getJSON("json/stats.json", function(result) {
|
fetch("json/stats.json")
|
||||||
$("#loading-notice").remove();
|
.then(response => {
|
||||||
if(result.reload)
|
if (!response.ok) {
|
||||||
setTimeout(function() { location.reload() }, 1000);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(result => {
|
||||||
|
document.getElementById("loading-notice")?.remove();
|
||||||
|
if (result.reload) setTimeout(location.reload, 1000);
|
||||||
|
|
||||||
for (var i = 0, rlen=result.servers.length; i < rlen; i++) {
|
result.servers.forEach((server, i) => {
|
||||||
var TableRow = $("#servers tr#r" + i);
|
let TableRow = document.querySelector(`#servers tr#r${i}`);
|
||||||
var ExpandRow = $("#servers #rt" + i);
|
let MableRow = document.querySelector(`#monitors tr#r${i}`);
|
||||||
var hack; // fuck CSS for making me do this
|
let ExpandRow = document.querySelector(`#servers #rt${i}`);
|
||||||
if(i%2) hack="odd"; else hack="even";
|
let hack = i % 2 ? "odd" : "even";
|
||||||
if (!TableRow.length) {
|
|
||||||
$("#servers").append(
|
|
||||||
"<tr id=\"r" + i + "\" data-toggle=\"collapse\" data-target=\"#rt" + i + "\" class=\"accordion-toggle " + hack + "\">" +
|
|
||||||
"<td id=\"online_status\"><div class=\"progress\"><div style=\"width: 100%;\" class=\"progress-bar progress-bar-warning\"><small>加载中</small></div></div></td>" +
|
|
||||||
"<td id=\"month_traffic\"><div class=\"progress\"><div style=\"width: 100%;\" class=\"progress-bar progress-bar-warning\"><small>加载中</small></div></div></td>" +
|
|
||||||
"<td id=\"name\">加载中</td>" +
|
|
||||||
"<td id=\"type\">加载中</td>" +
|
|
||||||
"<td id=\"location\">加载中</td>" +
|
|
||||||
"<td id=\"uptime\">加载中</td>" +
|
|
||||||
"<td id=\"load\">加载中</td>" +
|
|
||||||
"<td id=\"network\">加载中</td>" +
|
|
||||||
"<td id=\"traffic\">加载中</td>" +
|
|
||||||
"<td id=\"cpu\"><div class=\"progress\"><div style=\"width: 100%;\" class=\"progress-bar progress-bar-warning\"><small>加载中</small></div></div></td>" +
|
|
||||||
"<td id=\"memory\"><div class=\"progress\"><div style=\"width: 100%;\" class=\"progress-bar progress-bar-warning\"><small>加载中</small></div></div></td>" +
|
|
||||||
"<td id=\"hdd\"><div class=\"progress\"><div style=\"width: 100%;\" class=\"progress-bar progress-bar-warning\"><small>加载中</small></div></div></td>" +
|
|
||||||
"<td id=\"ping\"><div class=\"progress\"><div style=\"width: 100%;\" class=\"progress-bar progress-bar-warning\"><small>加载中</small></div></div></td>" +
|
|
||||||
"</tr>" +
|
|
||||||
"<tr class=\"expandRow " + hack + "\"><td colspan=\"16\"><div class=\"accordian-body collapse\" id=\"rt" + i + "\">" +
|
|
||||||
"<div id=\"expand_mem\">加载中</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>"
|
|
||||||
);
|
|
||||||
TableRow = $("#servers tr#r" + i);
|
|
||||||
ExpandRow = $("#servers #rt" + i);
|
|
||||||
server_status[i] = true;
|
|
||||||
}
|
|
||||||
TableRow = TableRow[0];
|
|
||||||
if(error) {
|
|
||||||
TableRow.setAttribute("data-target", "#rt" + i);
|
|
||||||
server_status[i] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// online_status
|
if (!TableRow) {
|
||||||
if (result.servers[i].online4 && !result.servers[i].online6) {
|
document.getElementById("servers").insertAdjacentHTML(
|
||||||
TableRow.children["online_status"].children[0].children[0].className = "progress-bar progress-bar-success";
|
"beforeend",
|
||||||
TableRow.children["online_status"].children[0].children[0].innerHTML = "<small>IPv4</small>";
|
`<tr id="r${i}" data-bs-toggle="collapse" data-bs-target="#rt${i}" class="accordion-toggle ${hack}">
|
||||||
} else if (result.servers[i].online4 && result.servers[i].online6) {
|
<td id="online_status"><div class="progress"><div style="width: 100%;" class="progress-bar bg-warning"><small>加载中</small></div></div></td>
|
||||||
TableRow.children["online_status"].children[0].children[0].className = "progress-bar progress-bar-success";
|
<td id="month_traffic"><div class="progress"><div style="width: 100%;" class="progress-bar bg-warning"><small>加载中</small></div></div></td>
|
||||||
TableRow.children["online_status"].children[0].children[0].innerHTML = "<small>双栈</small>";
|
<td id="name">加载中</td>
|
||||||
} else if (!result.servers[i].online4 && result.servers[i].online6) {
|
<td id="type">加载中</td>
|
||||||
TableRow.children["online_status"].children[0].children[0].className = "progress-bar progress-bar-success";
|
<td id="location">加载中</td>
|
||||||
TableRow.children["online_status"].children[0].children[0].innerHTML = "<small>IPv6</small>";
|
<td id="uptime">加载中</td>
|
||||||
} else {
|
<td id="load">加载中</td>
|
||||||
TableRow.children["online_status"].children[0].children[0].className = "progress-bar progress-bar-danger";
|
<td id="network">加载中</td>
|
||||||
TableRow.children["online_status"].children[0].children[0].innerHTML = "<small>关闭</small>";
|
<td id="traffic">加载中</td>
|
||||||
}
|
<td id="cpu"><div class="progress"><div style="width: 100%;" class="progress-bar bg-warning"><small>加载中</small></div></div></td>
|
||||||
|
<td id="memory"><div class="progress"><div style="width: 100%;" class="progress-bar bg-warning"><small>加载中</small></div></div></td>
|
||||||
|
<td id="hdd"><div class="progress"><div style="width: 100%;" class="progress-bar bg-warning"><small>加载中</small></div></div></td>
|
||||||
|
<td id="ping"><div class="progress"><div style="width: 100%;" class="progress-bar bg-warning"><small>加载中</small></div></div></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="expandRow ${hack}"><td colspan="16"><div class="accordian-body collapse" id="rt${i}">
|
||||||
|
<div id="expand_mem">加载中</div>
|
||||||
|
<div id="expand_hdd">加载中</div>
|
||||||
|
<div id="expand_tupd">加载中</div>
|
||||||
|
<div id="expand_ping">加载中</div>
|
||||||
|
</div></td></tr>`
|
||||||
|
);
|
||||||
|
TableRow = document.querySelector(`#servers tr#r${i}`);
|
||||||
|
ExpandRow = document.querySelector(`#servers #rt${i}`);
|
||||||
|
server_status[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Name
|
if (!MableRow) {
|
||||||
TableRow.children["name"].innerHTML = result.servers[i].name;
|
document.getElementById("monitors").insertAdjacentHTML(
|
||||||
|
"beforeend",
|
||||||
|
`<tr id="r${i}" data-bs-target="#rt${i}" class="accordion-toggle ${hack}">
|
||||||
|
<td id="monitor_status"><div class="progress"><div style="width: 100%;" class="progress-bar bg-warning"><small>加载中</small></div></div></td>
|
||||||
|
<td id="monitor_node">加载中</td>
|
||||||
|
<td id="monitor_location">加载中</td>
|
||||||
|
<td id="monitor_text">加载中</td>
|
||||||
|
</tr>`
|
||||||
|
);
|
||||||
|
MableRow = document.querySelector(`#monitors tr#r${i}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Type
|
if (error) {
|
||||||
TableRow.children["type"].innerHTML = result.servers[i].type;
|
TableRow.setAttribute("data-bs-target", `#rt${i}`);
|
||||||
|
MableRow.setAttribute("data-bs-target", `#rt${i}`);
|
||||||
|
server_status[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Location
|
const statusClass = server.online4 || server.online6 ? "progress-bar bg-success" : "progress-bar bg-danger";
|
||||||
TableRow.children["location"].innerHTML = result.servers[i].location;
|
const statusText = server.online4 && server.online6 ? "双栈" : server.online4 ? "IPv4" : server.online6 ? "IPv6" : "关闭";
|
||||||
if (!result.servers[i].online4 && !result.servers[i].online6) {
|
|
||||||
if (server_status[i]) {
|
|
||||||
TableRow.children["uptime"].innerHTML = "–";
|
|
||||||
TableRow.children["load"].innerHTML = "–";
|
|
||||||
TableRow.children["network"].innerHTML = "–";
|
|
||||||
TableRow.children["traffic"].innerHTML = "–";
|
|
||||||
TableRow.children["month_traffic"].children[0].children[0].className = "progress-bar progress-bar-warning";
|
|
||||||
TableRow.children["month_traffic"].children[0].children[0].innerHTML = "<small>关闭</small>";
|
|
||||||
TableRow.children["cpu"].children[0].children[0].className = "progress-bar progress-bar-danger";
|
|
||||||
TableRow.children["cpu"].children[0].children[0].style.width = "100%";
|
|
||||||
TableRow.children["cpu"].children[0].children[0].innerHTML = "<small>关闭</small>";
|
|
||||||
TableRow.children["memory"].children[0].children[0].className = "progress-bar progress-bar-danger";
|
|
||||||
TableRow.children["memory"].children[0].children[0].style.width = "100%";
|
|
||||||
TableRow.children["memory"].children[0].children[0].innerHTML = "<small>关闭</small>";
|
|
||||||
TableRow.children["hdd"].children[0].children[0].className = "progress-bar progress-bar-danger";
|
|
||||||
TableRow.children["hdd"].children[0].children[0].style.width = "100%";
|
|
||||||
TableRow.children["hdd"].children[0].children[0].innerHTML = "<small>关闭</small>";
|
|
||||||
TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-danger";
|
|
||||||
TableRow.children["ping"].children[0].children[0].style.width = "100%";
|
|
||||||
TableRow.children["ping"].children[0].children[0].innerHTML = "<small>关闭</small>";
|
|
||||||
if(ExpandRow.hasClass("in")) {
|
|
||||||
ExpandRow.collapse("hide");
|
|
||||||
}
|
|
||||||
TableRow.setAttribute("data-target", "");
|
|
||||||
server_status[i] = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!server_status[i]) {
|
|
||||||
TableRow.setAttribute("data-target", "#rt" + i);
|
|
||||||
server_status[i] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// month traffic
|
if (TableRow) {
|
||||||
var monthtraffic = "";
|
const onlineStatusBar = TableRow.querySelector("#online_status .progress-bar");
|
||||||
var trafficdiff_in = result.servers[i].network_in - result.servers[i].last_network_in;
|
if (onlineStatusBar) {
|
||||||
var trafficdiff_out = result.servers[i].network_out - result.servers[i].last_network_out;
|
onlineStatusBar.setAttribute("class", statusClass);
|
||||||
if(trafficdiff_in < 1024*1024*1024*1024)
|
onlineStatusBar.innerHTML = `<small>${statusText}</small>`;
|
||||||
monthtraffic += (trafficdiff_in/1024/1024/1024).toFixed(1) + "G";
|
}
|
||||||
else
|
}
|
||||||
monthtraffic += (trafficdiff_in/1024/1024/1024/1024).toFixed(1) + "T";
|
|
||||||
monthtraffic += " | "
|
|
||||||
if(trafficdiff_out < 1024*1024*1024*1024)
|
|
||||||
monthtraffic += (trafficdiff_out/1024/1024/1024).toFixed(1) + "G";
|
|
||||||
else
|
|
||||||
monthtraffic += (trafficdiff_out/1024/1024/1024/1024).toFixed(1) + "T";
|
|
||||||
TableRow.children["month_traffic"].children[0].children[0].className = "progress-bar progress-bar-success";
|
|
||||||
TableRow.children["month_traffic"].children[0].children[0].innerHTML = "<small>"+monthtraffic+"</small>";
|
|
||||||
|
|
||||||
// Uptime
|
if (MableRow) {
|
||||||
TableRow.children["uptime"].innerHTML = result.servers[i].uptime;
|
const monitorStatusBar = MableRow.querySelector("#monitor_status .progress-bar");
|
||||||
|
if (monitorStatusBar) {
|
||||||
|
monitorStatusBar.setAttribute("class", statusClass);
|
||||||
|
monitorStatusBar.innerHTML = `<small>${statusText}</small>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load: default load_1, you can change show: load_1, load_5, load_15
|
if (TableRow) {
|
||||||
if(result.servers[i].load == -1) {
|
TableRow.querySelector("#name").innerHTML = server.name;
|
||||||
TableRow.children["load"].innerHTML = "–";
|
TableRow.querySelector("#type").innerHTML = server.type;
|
||||||
} else {
|
TableRow.querySelector("#location").innerHTML = server.location;
|
||||||
TableRow.children["load"].innerHTML = result.servers[i].load_1.toFixed(2);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Network
|
if (MableRow) {
|
||||||
var netstr = "";
|
MableRow.querySelector("#monitor_node").innerHTML = server.name;
|
||||||
if(result.servers[i].network_rx < 1024*1024)
|
MableRow.querySelector("#monitor_location").innerHTML = server.location;
|
||||||
netstr += (result.servers[i].network_rx/1024).toFixed(1) + "K";
|
}
|
||||||
else
|
|
||||||
netstr += (result.servers[i].network_rx/1024/1024).toFixed(1) + "M";
|
|
||||||
netstr += " | "
|
|
||||||
if(result.servers[i].network_tx < 1024*1024)
|
|
||||||
netstr += (result.servers[i].network_tx/1024).toFixed(1) + "K";
|
|
||||||
else
|
|
||||||
netstr += (result.servers[i].network_tx/1024/1024).toFixed(1) + "M";
|
|
||||||
TableRow.children["network"].innerHTML = netstr;
|
|
||||||
|
|
||||||
//Traffic
|
if (!server.online4 && !server.online6) {
|
||||||
var trafficstr = "";
|
if (server_status[i]) {
|
||||||
if(result.servers[i].network_in < 1024*1024*1024*1024)
|
if (TableRow) {
|
||||||
trafficstr += (result.servers[i].network_in/1024/1024/1024).toFixed(1) + "G";
|
TableRow.querySelector("#uptime").innerHTML = "–";
|
||||||
else
|
TableRow.querySelector("#load").innerHTML = "–";
|
||||||
trafficstr += (result.servers[i].network_in/1024/1024/1024/1024).toFixed(1) + "T";
|
TableRow.querySelector("#network").innerHTML = "–";
|
||||||
trafficstr += " | "
|
TableRow.querySelector("#traffic").innerHTML = "–";
|
||||||
if(result.servers[i].network_out < 1024*1024*1024*1024)
|
const monthTrafficBar = TableRow.querySelector("#month_traffic .progress-bar");
|
||||||
trafficstr += (result.servers[i].network_out/1024/1024/1024).toFixed(1) + "G";
|
if (monthTrafficBar) {
|
||||||
else
|
monthTrafficBar.setAttribute("class", "progress-bar bg-warning");
|
||||||
trafficstr += (result.servers[i].network_out/1024/1024/1024/1024).toFixed(1) + "T";
|
monthTrafficBar.innerHTML = "<small>关闭</small>";
|
||||||
TableRow.children["traffic"].innerHTML = trafficstr;
|
}
|
||||||
|
const cpuBar = TableRow.querySelector("#cpu .progress-bar");
|
||||||
|
if (cpuBar) {
|
||||||
|
cpuBar.setAttribute("class", "progress-bar bg-danger");
|
||||||
|
cpuBar.style.width = "100%";
|
||||||
|
cpuBar.innerHTML = "<small>关闭</small>";
|
||||||
|
}
|
||||||
|
const memoryBar = TableRow.querySelector("#memory .progress-bar");
|
||||||
|
if (memoryBar) {
|
||||||
|
memoryBar.setAttribute("class", "progress-bar bg-danger");
|
||||||
|
memoryBar.style.width = "100%";
|
||||||
|
memoryBar.innerHTML = "<small>关闭</small>";
|
||||||
|
}
|
||||||
|
const hddBar = TableRow.querySelector("#hdd .progress-bar");
|
||||||
|
if (hddBar) {
|
||||||
|
hddBar.setAttribute("class", "progress-bar bg-danger");
|
||||||
|
hddBar.style.width = "100%";
|
||||||
|
hddBar.innerHTML = "<small>关闭</small>";
|
||||||
|
}
|
||||||
|
const pingBar = TableRow.querySelector("#ping .progress-bar");
|
||||||
|
if (pingBar) {
|
||||||
|
pingBar.setAttribute("class", "progress-bar bg-danger");
|
||||||
|
pingBar.style.width = "100%";
|
||||||
|
pingBar.innerHTML = "<small>关闭</small>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (MableRow) {
|
||||||
|
MableRow.querySelector("#monitor_text").innerHTML = "-";
|
||||||
|
}
|
||||||
|
if (ExpandRow && ExpandRow.classList.contains("show")) ExpandRow.classList.remove("show");
|
||||||
|
if (TableRow) TableRow.setAttribute("data-bs-target", "");
|
||||||
|
if (MableRow) MableRow.setAttribute("data-bs-target", "");
|
||||||
|
server_status[i] = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!server_status[i]) {
|
||||||
|
if (TableRow) TableRow.setAttribute("data-bs-target", `#rt${i}`);
|
||||||
|
if (MableRow) MableRow.setAttribute("data-bs-target", `#rt${i}`);
|
||||||
|
server_status[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
// CPU
|
const trafficdiff_in = server.network_in - server.last_network_in;
|
||||||
if (result.servers[i].cpu >= 90)
|
const trafficdiff_out = server.network_out - server.last_network_out;
|
||||||
TableRow.children["cpu"].children[0].children[0].className = "progress-bar progress-bar-danger";
|
const monthtraffic = `${bytesToSize(trafficdiff_in, 1, true)} | ${bytesToSize(trafficdiff_out, 1, true)}`;
|
||||||
else if (result.servers[i].cpu >= 80)
|
if (TableRow) {
|
||||||
TableRow.children["cpu"].children[0].children[0].className = "progress-bar progress-bar-warning";
|
const monthTrafficBar = TableRow.querySelector("#month_traffic .progress-bar");
|
||||||
else
|
if (monthTrafficBar) {
|
||||||
TableRow.children["cpu"].children[0].children[0].className = "progress-bar progress-bar-success";
|
monthTrafficBar.setAttribute("class", "progress-bar bg-success");
|
||||||
TableRow.children["cpu"].children[0].children[0].style.width = result.servers[i].cpu + "%";
|
monthTrafficBar.innerHTML = `<small>${monthtraffic}</small>`;
|
||||||
TableRow.children["cpu"].children[0].children[0].innerHTML = result.servers[i].cpu + "%";
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Memory
|
if (TableRow) TableRow.querySelector("#uptime").innerHTML = server.uptime;
|
||||||
var Mem = ((result.servers[i].memory_used/result.servers[i].memory_total)*100.0).toFixed(0);
|
if (TableRow) TableRow.querySelector("#load").innerHTML = server.load_1 == -1 ? "–" : server.load_1.toFixed(2);
|
||||||
if (Mem >= 90)
|
|
||||||
TableRow.children["memory"].children[0].children[0].className = "progress-bar progress-bar-danger";
|
|
||||||
else if (Mem >= 80)
|
|
||||||
TableRow.children["memory"].children[0].children[0].className = "progress-bar progress-bar-warning";
|
|
||||||
else
|
|
||||||
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 + "%";
|
|
||||||
// 内存|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
|
const netstr = `${bytesToSize(server.network_rx, 1, true)} | ${bytesToSize(server.network_tx, 1, true)}`;
|
||||||
var HDD = ((result.servers[i].hdd_used/result.servers[i].hdd_total)*100.0).toFixed(0);
|
if (TableRow) TableRow.querySelector("#network").innerHTML = netstr;
|
||||||
if (HDD >= 90)
|
|
||||||
TableRow.children["hdd"].children[0].children[0].className = "progress-bar progress-bar-danger";
|
|
||||||
else if (HDD >= 80)
|
|
||||||
TableRow.children["hdd"].children[0].children[0].className = "progress-bar progress-bar-warning";
|
|
||||||
else
|
|
||||||
TableRow.children["hdd"].children[0].children[0].className = "progress-bar progress-bar-success";
|
|
||||||
TableRow.children["hdd"].children[0].children[0].style.width = HDD + "%";
|
|
||||||
TableRow.children["hdd"].children[0].children[0].innerHTML = HDD + "%";
|
|
||||||
// IO Speed for HDD.
|
|
||||||
// IO, 过小的B字节单位没有意义
|
|
||||||
var io = "";
|
|
||||||
if(result.servers[i].io_read < 1024*1024)
|
|
||||||
io += parseInt(result.servers[i].io_read/1024) + "K";
|
|
||||||
else
|
|
||||||
io += parseInt(result.servers[i].io_read/1024/1024) + "M";
|
|
||||||
io += " / "
|
|
||||||
if(result.servers[i].io_write < 1024*1024)
|
|
||||||
io += parseInt(result.servers[i].io_write/1024) + "K";
|
|
||||||
else
|
|
||||||
io += parseInt(result.servers[i].io_write/1024/1024) + "M";
|
|
||||||
// Expand for HDD.
|
|
||||||
ExpandRow[0].children["expand_hdd"].innerHTML = "硬盘|读写: " + bytesToSize(result.servers[i].hdd_used*1024*1024, 2) + " / " + bytesToSize(result.servers[i].hdd_total*1024*1024, 2) + " | " + io;
|
|
||||||
|
|
||||||
// delay time
|
const trafficstr = `${bytesToSize(server.network_in, 1, true)} | ${bytesToSize(server.network_out, 1, true)}`;
|
||||||
|
if (TableRow) TableRow.querySelector("#traffic").innerHTML = trafficstr;
|
||||||
|
|
||||||
// tcp, udp, process, thread count
|
const cpuClass = server.cpu >= 90 ? "progress-bar bg-danger" : server.cpu >= 80 ? "progress-bar bg-warning" : "progress-bar bg-success";
|
||||||
ExpandRow[0].children["expand_tupd"].innerHTML = "TCP/UDP/进/线: " + result.servers[i].tcp_count + " / " + result.servers[i].udp_count + " / " + result.servers[i].process_count+ " / " + result.servers[i].thread_count;
|
if (TableRow) {
|
||||||
ExpandRow[0].children["expand_ping"].innerHTML = "联通/电信/移动: " + result.servers[i].time_10010 + "ms / " + result.servers[i].time_189 + "ms / " + result.servers[i].time_10086 + "ms"
|
const cpuBar = TableRow.querySelector("#cpu .progress-bar");
|
||||||
|
if (cpuBar) {
|
||||||
|
cpuBar.setAttribute("class", cpuClass);
|
||||||
|
cpuBar.style.width = `${server.cpu}%`;
|
||||||
|
cpuBar.innerHTML = `${server.cpu}%`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ping
|
const Mem = ((server.memory_used / server.memory_total) * 100).toFixed(0);
|
||||||
var PING_10010 = result.servers[i].ping_10010.toFixed(0);
|
const memClass = Mem >= 90 ? "progress-bar bg-danger" : Mem >= 80 ? "progress-bar bg-warning" : "progress-bar bg-success";
|
||||||
var PING_189 = result.servers[i].ping_189.toFixed(0);
|
if (TableRow) {
|
||||||
var PING_10086 = result.servers[i].ping_10086.toFixed(0);
|
const memoryBar = TableRow.querySelector("#memory .progress-bar");
|
||||||
ExpandRow[0].children["expand_lost"].innerHTML = "丢包:联通/电信/移动: " + PING_10010 + "% / " + PING_189 + "% / " + PING_10086 + "%"
|
if (memoryBar) {
|
||||||
|
memoryBar.setAttribute("class", memClass);
|
||||||
|
memoryBar.style.width = `${Mem}%`;
|
||||||
|
memoryBar.innerHTML = `${Mem}%`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ExpandRow) ExpandRow.querySelector("#expand_mem").innerHTML = `内存|虚存: ${bytesToSize(server.memory_used * 1024, 1)} / ${bytesToSize(server.memory_total * 1024, 1)} | ${bytesToSize(server.swap_used * 1024, 0)} / ${bytesToSize(server.swap_total * 1024, 0)}`;
|
||||||
|
|
||||||
if (PING_10010 >= 20 || PING_189 >= 20 || PING_10086 >= 20)
|
const HDD = ((server.hdd_used / server.hdd_total) * 100).toFixed(0);
|
||||||
TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-danger";
|
const hddClass = HDD >= 90 ? "progress-bar bg-danger" : HDD >= 80 ? "progress-bar bg-warning" : "progress-bar bg-success";
|
||||||
else if (PING_10010 >= 10 || PING_189 >= 10 || PING_10086 >= 10)
|
if (TableRow) {
|
||||||
TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-warning";
|
const hddBar = TableRow.querySelector("#hdd .progress-bar");
|
||||||
else
|
if (hddBar) {
|
||||||
TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-success";
|
hddBar.setAttribute("class", hddClass);
|
||||||
TableRow.children["ping"].children[0].children[0].innerHTML = PING_10010 + "%💻" + PING_189 + "%💻" + PING_10086 + "%";
|
hddBar.style.width = `${HDD}%`;
|
||||||
|
hddBar.innerHTML = `${HDD}%`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const io = `${bytesToSize(server.io_read, 0, true)} / ${bytesToSize(server.io_write, 0, true)}`;
|
||||||
|
if (ExpandRow) ExpandRow.querySelector("#expand_hdd").innerHTML = `硬盘|读写: ${bytesToSize(server.hdd_used * 1024 * 1024, 2)} / ${bytesToSize(server.hdd_total * 1024 * 1024, 2)} | ${io}`;
|
||||||
|
|
||||||
// Custom
|
if (ExpandRow) ExpandRow.querySelector("#expand_tupd").innerHTML = `TCP/UDP/进/线: ${server.tcp_count} / ${server.udp_count} / ${server.process_count} / ${server.thread_count}`;
|
||||||
if (result.servers[i].custom) {
|
|
||||||
ExpandRow[0].children["expand_custom"].innerHTML = result.servers[i].custom
|
|
||||||
} else {
|
|
||||||
ExpandRow[0].children["expand_custom"].innerHTML = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
d = new Date(result.updated*1000);
|
const PING_10010 = server.ping_10010.toFixed(0);
|
||||||
error = 0;
|
const PING_189 = server.ping_189.toFixed(0);
|
||||||
}).fail(function(update_error) {
|
const PING_10086 = server.ping_10086.toFixed(0);
|
||||||
if (!error) {
|
const pingClass = PING_10010 >= 20 || PING_189 >= 20 || PING_10086 >= 20 ? "progress-bar bg-danger" : PING_10010 >= 10 || PING_189 >= 10 || PING_10086 >= 10 ? "progress-bar bg-warning" : "progress-bar bg-success";
|
||||||
$("#servers > tr.accordion-toggle").each(function(i) {
|
if (TableRow) {
|
||||||
var TableRow = $("#servers tr#r" + i)[0];
|
const pingBar = TableRow.querySelector("#ping .progress-bar");
|
||||||
var ExpandRow = $("#servers #rt" + i);
|
if (pingBar) {
|
||||||
TableRow.children["online_status"].children[0].children[0].className = "progress-bar progress-bar-error";
|
pingBar.setAttribute("class", pingClass);
|
||||||
TableRow.children["online_status"].children[0].children[0].innerHTML = "<small>错误</small>";
|
pingBar.innerHTML = `${PING_10010}%💻${PING_189}%💻${PING_10086}%`;
|
||||||
TableRow.children["month_traffic"].children[0].children[0].className = "progress-bar progress-bar-error";
|
}
|
||||||
TableRow.children["month_traffic"].children[0].children[0].innerHTML = "<small>错误</small>";
|
}
|
||||||
TableRow.children["uptime"].children[0].children[0].className = "progress-bar progress-bar-error";
|
if (ExpandRow) ExpandRow.querySelector("#expand_ping").innerHTML = `CU/CT/CM: ${server.time_10010}ms (${PING_10010}%) / ${server.time_189}ms (${PING_189}%) / ${server.time_10086}ms (${PING_10086}%)`;
|
||||||
TableRow.children["uptime"].children[0].children[0].innerHTML = "<small>错误</small>";
|
|
||||||
TableRow.children["load"].children[0].children[0].className = "progress-bar progress-bar-error";
|
if (MableRow) MableRow.querySelector("#monitor_text").innerHTML = server.custom;
|
||||||
TableRow.children["load"].children[0].children[0].innerHTML = "<small>错误</small>";
|
}
|
||||||
TableRow.children["network"].children[0].children[0].className = "progress-bar progress-bar-error";
|
});
|
||||||
TableRow.children["network"].children[0].children[0].innerHTML = "<small>错误</small>";
|
|
||||||
TableRow.children["traffic"].children[0].children[0].className = "progress-bar progress-bar-error";
|
d = new Date(result.updated * 1000);
|
||||||
TableRow.children["traffic"].children[0].children[0].innerHTML = "<small>错误</small>";
|
error = 0;
|
||||||
TableRow.children["cpu"].children[0].children[0].className = "progress-bar progress-bar-error";
|
})
|
||||||
TableRow.children["cpu"].children[0].children[0].style.width = "100%";
|
.catch(error => {
|
||||||
TableRow.children["cpu"].children[0].children[0].innerHTML = "<small>错误</small>";
|
console.error("Fetch error: ", error);
|
||||||
TableRow.children["memory"].children[0].children[0].className = "progress-bar progress-bar-error";
|
if (!error) {
|
||||||
TableRow.children["memory"].children[0].children[0].style.width = "100%";
|
document.querySelectorAll("#servers > tr.accordion-toggle").forEach((TableRow, i) => {
|
||||||
TableRow.children["memory"].children[0].children[0].innerHTML = "<small>错误</small>";
|
const MableRow = document.querySelector(`#monitors tr#r${i}`);
|
||||||
TableRow.children["hdd"].children[0].children[0].className = "progress-bar progress-bar-error";
|
const ExpandRow = document.querySelector(`#servers #rt${i}`);
|
||||||
TableRow.children["hdd"].children[0].children[0].style.width = "100%";
|
|
||||||
TableRow.children["hdd"].children[0].children[0].innerHTML = "<small>错误</small>";
|
if (TableRow && MableRow) {
|
||||||
TableRow.children["ping"].children[0].children[0].className = "progress-bar progress-bar-error";
|
TableRow.querySelectorAll(".progress-bar").forEach(bar => {
|
||||||
TableRow.children["ping"].children[0].children[0].style.width = "100%";
|
if (bar) {
|
||||||
TableRow.children["ping"].children[0].children[0].innerHTML = "<small>错误</small>";
|
bar.setAttribute("class", "progress-bar bg-danger");
|
||||||
if(ExpandRow.hasClass("in")) {
|
bar.innerHTML = "<small>错误</small>";
|
||||||
ExpandRow.collapse("hide");
|
}
|
||||||
}
|
});
|
||||||
TableRow.setAttribute("data-target", "");
|
|
||||||
server_status[i] = false;
|
MableRow.querySelectorAll(".progress-bar").forEach(bar => {
|
||||||
});
|
if (bar) {
|
||||||
}
|
bar.setAttribute("class", "progress-bar bg-danger");
|
||||||
error = 1;
|
bar.innerHTML = "<small>错误</small>";
|
||||||
$("#updated").html("更新错误.");
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (ExpandRow && ExpandRow.classList.contains("show")) {
|
||||||
|
ExpandRow.classList.remove("show");
|
||||||
|
}
|
||||||
|
|
||||||
|
TableRow.setAttribute("data-bs-target", "");
|
||||||
|
MableRow.setAttribute("data-bs-target", "");
|
||||||
|
server_status[i] = false;
|
||||||
|
} else {
|
||||||
|
console.error(`TableRow or MableRow is undefined for index ${i}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
error = 1;
|
||||||
|
document.getElementById("updated").innerHTML = "更新错误.";
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTime() {
|
function updateTime() {
|
||||||
if (!error)
|
if (!error) document.getElementById("updated").innerHTML = "最后更新: " + timeSince(d);
|
||||||
$("#updated").html("最后更新: " + timeSince(d));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uptime();
|
uptime();
|
||||||
updateTime();
|
updateTime();
|
||||||
|
// 降低改值,可以减少cpu占用
|
||||||
setInterval(uptime, 2000);
|
setInterval(uptime, 2000);
|
||||||
setInterval(updateTime, 2000);
|
setInterval(updateTime, 2000);
|
||||||
|
|
||||||
|
|
||||||
// styleswitcher.js
|
// styleswitcher.js
|
||||||
function setActiveStyleSheet(title, cookie=false) {
|
function setActiveStyleSheet(title) {
|
||||||
var i, a, main;
|
var i, a, main;
|
||||||
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
|
for (i = 0; (a = document.getElementsByTagName("link")[i]); i++) {
|
||||||
if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) {
|
if (a.getAttribute("rel").indexOf("stylesheet") != -1 && a.getAttribute("title")) {
|
||||||
a.disabled = true;
|
a.disabled = true;
|
||||||
if(a.getAttribute("title") == title) a.disabled = false;
|
if (a.getAttribute("title") == title) a.disabled = false;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (true==cookie) {
|
|
||||||
createCookie("style", title, 365);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveStyleSheet() {
|
function getActiveStyleSheet() {
|
||||||
var i, a;
|
return Array.from(document.getElementsByTagName("link")).find(a => a.getAttribute("rel").includes("style") && a.getAttribute("title") && !a.disabled)?.getAttribute("title") || null;
|
||||||
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
|
|
||||||
if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title") && !a.disabled)
|
|
||||||
return a.getAttribute("title");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createCookie(name,value,days) {
|
function createCookie(name, value, days) {
|
||||||
if (days) {
|
const expires = days ? `; expires=${new Date(Date.now() + days * 24 * 60 * 60 * 1000).toGMTString()}` : "";
|
||||||
var date = new Date();
|
document.cookie = `${name}=${value}${expires}; path=/`;
|
||||||
date.setTime(date.getTime()+(days*24*60*60*1000));
|
|
||||||
var expires = "; expires="+date.toGMTString();
|
|
||||||
}
|
|
||||||
else expires = "";
|
|
||||||
document.cookie = name+"="+value+expires+"; path=/";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function readCookie(name) {
|
function readCookie(name) {
|
||||||
var nameEQ = name + "=";
|
const nameEQ = name + "=";
|
||||||
var ca = document.cookie.split(';');
|
const ca = document.cookie.split(';');
|
||||||
for(var i=0;i < ca.length;i++) {
|
for (let i = 0; i < ca.length; i++) {
|
||||||
var c = ca[i];
|
let c = ca[i];
|
||||||
while (c.charAt(0)==' ')
|
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
||||||
c = c.substring(1,c.length);
|
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
||||||
if (c.indexOf(nameEQ) == 0)
|
}
|
||||||
return c.substring(nameEQ.length,c.length);
|
return null;
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onload = function(e) {
|
window.onload = function() {
|
||||||
var cookie = readCookie("style");
|
const cookie = readCookie("style");
|
||||||
if (cookie && cookie != 'null' ) {
|
if (cookie && cookie != 'null') {
|
||||||
setActiveStyleSheet(cookie);
|
setActiveStyleSheet(cookie);
|
||||||
} else {
|
} else {
|
||||||
function handleChange (mediaQueryListEvent) {
|
const handleChange = mediaQueryListEvent => setActiveStyleSheet(mediaQueryListEvent.matches ? 'dark' : 'light');
|
||||||
if (mediaQueryListEvent.matches) {
|
const mediaQueryListDark = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
setActiveStyleSheet('dark');
|
setActiveStyleSheet(mediaQueryListDark.matches ? 'dark' : 'light');
|
||||||
} else {
|
mediaQueryListDark.addEventListener("change", handleChange);
|
||||||
setActiveStyleSheet('light');
|
}
|
||||||
}
|
|
||||||
}
|
// 处理标签页切换
|
||||||
const mediaQueryListDark = window.matchMedia('(prefers-color-scheme: dark)');
|
const tabs = document.querySelectorAll('.nav-link');
|
||||||
setActiveStyleSheet(mediaQueryListDark.matches ? 'dark' : 'light');
|
tabs.forEach(tab => {
|
||||||
mediaQueryListDark.addEventListener("change",handleChange);
|
tab.addEventListener('click', function(event) {
|
||||||
}
|
if (this.id === 'navbarDropdown') {
|
||||||
}
|
return; // 阻止“风格”标签的默认行为
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
const target = this.getAttribute('href');
|
||||||
|
document.querySelectorAll('.tab-pane').forEach(pane => pane.classList.remove('show', 'active'));
|
||||||
|
document.querySelector(target).classList.add('show', 'active');
|
||||||
|
tabs.forEach(t => t.classList.remove('active'));
|
||||||
|
this.classList.add('active');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user