Skip to content

Commit f7b2e7d

Browse files
authored
Merge pull request #242 from cppla/dev
1.1.2 测试
2 parents 4a9f5ad + 052c75e commit f7b2e7d

File tree

10 files changed

+471
-151
lines changed

10 files changed

+471
-151
lines changed

README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
[![Python Support](https://img.shields.io/badge/python-3.6%2B%20-blue.svg)](https://github.com/cppla/ServerStatus)
77
[![C++ Compiler](http://img.shields.io/badge/C++-GNU-blue.svg?style=flat&logo=cplusplus)](https://github.com/cppla/ServerStatus)
88
[![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/cppla/ServerStatus)
9-
[![Version](https://img.shields.io/badge/Version-Build%201.1.1-red)](https://github.com/cppla/ServerStatus)
9+
[![Version](https://img.shields.io/badge/Version-Build%201.1.2-red)](https://github.com/cppla/ServerStatus)
1010

1111
![Latest Version](http://dl.cpp.la/Archive/serverstatus_1.0.9.png)
1212

13-
`Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。 同时为了防止海外机器闪断报警,也加入username、name、type等静态字符串参数的计算支持。`
13+
`Watchdog触发式告警,interval只是为了防止频繁收到报警信息造成的骚扰,并不是探测间隔。 同时为了防止海外机器闪断报警,也加入username、name、type等静态字符串参数的计算支持。值得注意的是,Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复 `
1414

1515
# 目录:
1616

@@ -67,7 +67,7 @@ cd ServerStatus/server && make
6767

6868
#### 二、修改配置文件
6969
```diff
70-
! watchdog rule 可以为任何已知字段的表达式
70+
! watchdog rule 可以为任何已知字段的表达式。注意Exprtk库默认使用窄字符类型,中文等Unicode字符无法解析计算,等待修复
7171
! watchdog interval 最小通知间隔
7272
! watchdog callback 可自定义为Post方法的URL,告警内容将拼接其后并发起回调
7373

@@ -89,13 +89,21 @@ cd ServerStatus/server && make
8989
"location": "🇨🇳",
9090
"password": "USER_DEFAULT_PASSWORD",
9191
"monthstart": 1
92-
},
92+
}
93+
],
94+
"monitors": [
95+
{
96+
"name": "监测网站以及MySQL、Redis,默认为七天在线率",
97+
"host": "https://www.baidu.com",
98+
"interval": 60,
99+
"type": "https"
100+
}
93101
],
94102
"watchdog":
95103
[
96104
{
97-
"name": "服务器负载高监控,排除内存大于32G物理机,同时排除俄勒冈机器",
98-
"rule": "cpu>90&load_1>4&memory_total<33554432&name!='俄勒冈'",
105+
"name": "服务器负载高监控,排除内存大于32G物理机,同时排除node1机器",
106+
"rule": "cpu>90&load_1>4&memory_total<33554432&name!='node1'",
99107
"interval": 600,
100108
"callback": "https://yourSMSurl"
101109
},
@@ -106,8 +114,8 @@ cd ServerStatus/server && make
106114
"callback": "https://yourSMSurl"
107115
},
108116
{
109-
"name": "服务器宕机告警,排出俄勒冈,排除s02",
110-
"rule": "online4=0&online6=0&name!='俄勒冈'&username!='s02'",
117+
"name": "服务器宕机告警,排出node1,排除s02",
118+
"rule": "online4=0&online6=0&name!='node1'&username!='s02'",
111119
"interval": 600,
112120
"callback": "https://yourSMSurl"
113121
},

clients/client-linux.py

Lines changed: 118 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Update by : https://github.com/cppla/ServerStatus, Update date: 20220530
44
# 版本:1.0.3, 支持Python版本:2.7 to 3.10
55
# 支持操作系统: Linux, OSX, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures
6+
# ONLINE_PACKET_HISTORY_LEN, 探测间隔60s,记录24小时在线率(1440);探测间隔60s,记录7天(10080);探测时间30s,记录24小时(2880)
67
# 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。
78

89
SERVER = "127.0.0.1"
@@ -17,9 +18,11 @@
1718
PROBEPORT = 80
1819
PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6
1920
PING_PACKET_HISTORY_LEN = 100
21+
ONLINE_PACKET_HISTORY_LEN = 10080
2022
INTERVAL = 1
2123

2224
import socket
25+
import ssl
2326
import time
2427
import timeit
2528
import re
@@ -29,10 +32,10 @@
2932
import errno
3033
import subprocess
3134
import threading
32-
try:
33-
from queue import Queue # python3
34-
except ImportError:
35-
from Queue import Queue # python2
35+
if sys.version_info.major == 3:
36+
from queue import Queue
37+
elif sys.version_info.major == 2:
38+
from Queue import Queue
3639

3740
def get_uptime():
3841
with open('/proc/uptime', 'r') as f:
@@ -150,6 +153,7 @@ def get_network(ip_version):
150153
'read': 0,
151154
'write': 0
152155
}
156+
monitorServer = {}
153157

154158
def _ping_thread(host, mark, port):
155159
lostPacket = 0
@@ -314,6 +318,91 @@ def get_realtime_data():
314318
ti.daemon = True
315319
ti.start()
316320

321+
322+
def _monitor_thread(name, host, interval, type):
323+
lostPacket = 0
324+
packet_queue = Queue(maxsize=ONLINE_PACKET_HISTORY_LEN)
325+
while True:
326+
if name not in monitorServer.keys():
327+
break
328+
if packet_queue.full():
329+
if packet_queue.get() == 0:
330+
lostPacket -= 1
331+
try:
332+
if type == "http":
333+
address = host.replace("http://", "")
334+
m = timeit.default_timer()
335+
if PROBE_PROTOCOL_PREFER == 'ipv4':
336+
IP = socket.getaddrinfo(address, None, socket.AF_INET)[0][4][0]
337+
else:
338+
IP = socket.getaddrinfo(address, None, socket.AF_INET6)[0][4][0]
339+
monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000)
340+
m = timeit.default_timer()
341+
k = socket.create_connection((IP, 80), timeout=6)
342+
monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000)
343+
m = timeit.default_timer()
344+
k.sendall("GET / HTTP/1.2\r\nHost:{}\r\nConnection:close\r\n\r\n".format(address).encode('utf-8'))
345+
response = b""
346+
while True:
347+
data = k.recv(4096)
348+
if not data:
349+
break
350+
response += data
351+
http_code = response.decode('utf-8').split('\r\n')[0].split()[1]
352+
monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000)
353+
k.close()
354+
if http_code not in ['200', '204', '301', '302', '401']:
355+
raise Exception("http code not in 200, 204, 301, 302, 401")
356+
elif type == "https":
357+
context = ssl._create_unverified_context()
358+
address = host.replace("https://", "")
359+
m = timeit.default_timer()
360+
if PROBE_PROTOCOL_PREFER == 'ipv4':
361+
IP = socket.getaddrinfo(address, None, socket.AF_INET)[0][4][0]
362+
else:
363+
IP = socket.getaddrinfo(address, None, socket.AF_INET6)[0][4][0]
364+
monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000)
365+
m = timeit.default_timer()
366+
k = socket.create_connection((IP, 443), timeout=6)
367+
monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000)
368+
m = timeit.default_timer()
369+
kk = context.wrap_socket(k, server_hostname=address)
370+
kk.sendall("GET / HTTP/1.2\r\nHost:{}\r\nConnection:close\r\n\r\n".format(address).encode('utf-8'))
371+
response = b""
372+
while True:
373+
data = kk.recv(4096)
374+
if not data:
375+
break
376+
response += data
377+
http_code = response.decode('utf-8').split('\r\n')[0].split()[1]
378+
monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000)
379+
kk.close()
380+
k.close()
381+
if http_code not in ['200', '204', '301', '302', '401']:
382+
raise Exception("http code not in 200, 204, 301, 302, 401")
383+
elif type == "tcp":
384+
m = timeit.default_timer()
385+
if PROBE_PROTOCOL_PREFER == 'ipv4':
386+
IP = socket.getaddrinfo(host.split(":")[0], None, socket.AF_INET)[0][4][0]
387+
else:
388+
IP = socket.getaddrinfo(host.split(":")[0], None, socket.AF_INET6)[0][4][0]
389+
monitorServer[name]["dns_time"] = int((timeit.default_timer() - m) * 1000)
390+
m = timeit.default_timer()
391+
k = socket.create_connection((IP, int(host.split(":")[1])), timeout=6)
392+
monitorServer[name]["connect_time"] = int((timeit.default_timer() - m) * 1000)
393+
m = timeit.default_timer()
394+
k.send(b"GET / HTTP/1.2\r\n\r\n")
395+
k.recv(1024)
396+
monitorServer[name]["download_time"] = int((timeit.default_timer() - m) * 1000)
397+
k.close()
398+
packet_queue.put(1)
399+
except Exception as e:
400+
lostPacket += 1
401+
packet_queue.put(0)
402+
if packet_queue.qsize() > 5:
403+
monitorServer[name]["online_rate"] = 1 - float(lostPacket) / packet_queue.qsize()
404+
time.sleep(interval)
405+
317406
def byte_str(object):
318407
'''
319408
bytes to str, str to bytes
@@ -360,6 +449,28 @@ def byte_str(object):
360449
if data.find("You are connecting via") < 0:
361450
data = byte_str(s.recv(1024))
362451
print(data)
452+
monitorServer.clear()
453+
for i in data.split('\n'):
454+
if "monitor" in i and "type" in i and "{" in i and "}" in i:
455+
jdata = json.loads(i[i.find("{"):i.find("}")+1])
456+
monitorServer[jdata.get("name")] = {
457+
"type": jdata.get("type"),
458+
"dns_time": 0,
459+
"connect_time": 0,
460+
"download_time": 0,
461+
"online_rate": 1
462+
}
463+
t = threading.Thread(
464+
target=_monitor_thread,
465+
kwargs={
466+
'name': jdata.get("name"),
467+
'host': jdata.get("host"),
468+
'interval': jdata.get("interval"),
469+
'type': jdata.get("type")
470+
}
471+
)
472+
t.daemon = True
473+
t.start()
363474

364475
timer = 0
365476
check_ip = 0
@@ -378,7 +489,6 @@ def byte_str(object):
378489
Load_1, Load_5, Load_15 = os.getloadavg()
379490
MemoryTotal, MemoryUsed, SwapTotal, SwapFree = get_memory()
380491
HDDTotal, HDDUsed = get_hdd()
381-
382492
array = {}
383493
if not timer:
384494
array['online' + str(check_ip)] = get_network(check_ip)
@@ -401,8 +511,6 @@ def byte_str(object):
401511
array['network_tx'] = netSpeed.get("nettx")
402512
array['network_in'] = NET_IN
403513
array['network_out'] = NET_OUT
404-
# todo:兼容旧版本,下个版本删除ip_status
405-
array['ip_status'] = True
406514
array['ping_10010'] = lostRate.get('10010') * 100
407515
array['ping_189'] = lostRate.get('189') * 100
408516
array['ping_10086'] = lostRate.get('10086') * 100
@@ -412,16 +520,18 @@ def byte_str(object):
412520
array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
413521
array['io_read'] = diskIO.get("read")
414522
array['io_write'] = diskIO.get("write")
415-
523+
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())
416524
s.send(byte_str("update " + json.dumps(array) + "\n"))
417525
except KeyboardInterrupt:
418526
raise
419527
except socket.error:
528+
monitorServer.clear()
420529
print("Disconnected...")
421530
if 's' in locals().keys():
422531
del s
423532
time.sleep(3)
424533
except Exception as e:
534+
monitorServer.clear()
425535
print("Caught Exception:", e)
426536
if 's' in locals().keys():
427537
del s

0 commit comments

Comments
 (0)