client-linux.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. #!/usr/bin/env python3
  2. # coding: utf-8
  3. # Update by : https://github.com/cppla/ServerStatus, Update date: 20220530
  4. # 版本:1.0.3, 支持Python版本:2.7 to 3.10
  5. # 支持操作系统: Linux, OSX, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures
  6. # 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。
  7. SERVER = "127.0.0.1"
  8. USER = "s01"
  9. PASSWORD = "USER_DEFAULT_PASSWORD"
  10. PORT = 35601
  11. CU = "cu.tz.cloudcpp.com"
  12. CT = "ct.tz.cloudcpp.com"
  13. CM = "cm.tz.cloudcpp.com"
  14. PROBEPORT = 80
  15. PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6
  16. PING_PACKET_HISTORY_LEN = 100
  17. INTERVAL = 1
  18. import socket
  19. import time
  20. import timeit
  21. import re
  22. import os
  23. import sys
  24. import json
  25. import errno
  26. import subprocess
  27. import threading
  28. try:
  29. from queue import Queue # python3
  30. except ImportError:
  31. from Queue import Queue # python2
  32. def get_uptime():
  33. with open('/proc/uptime', 'r') as f:
  34. uptime = f.readline().split('.', 2)
  35. return int(uptime[0])
  36. def get_memory():
  37. re_parser = re.compile(r'^(?P<key>\S*):\s*(?P<value>\d*)\s*kB')
  38. result = dict()
  39. for line in open('/proc/meminfo'):
  40. match = re_parser.match(line)
  41. if not match:
  42. continue
  43. key, value = match.groups(['key', 'value'])
  44. result[key] = int(value)
  45. MemTotal = float(result['MemTotal'])
  46. MemUsed = MemTotal-float(result['MemFree'])-float(result['Buffers'])-float(result['Cached'])-float(result['SReclaimable'])
  47. SwapTotal = float(result['SwapTotal'])
  48. SwapFree = float(result['SwapFree'])
  49. return int(MemTotal), int(MemUsed), int(SwapTotal), int(SwapFree)
  50. def get_hdd():
  51. p = subprocess.check_output(['df', '-Tlm', '--total', '-t', 'ext4', '-t', 'ext3', '-t', 'ext2', '-t', 'reiserfs', '-t', 'jfs', '-t', 'ntfs', '-t', 'fat32', '-t', 'btrfs', '-t', 'fuseblk', '-t', 'zfs', '-t', 'simfs', '-t', 'xfs']).decode("Utf-8")
  52. total = p.splitlines()[-1]
  53. used = total.split()[3]
  54. size = total.split()[2]
  55. return int(size), int(used)
  56. def get_time():
  57. with open("/proc/stat", "r") as f:
  58. time_list = f.readline().split(' ')[2:6]
  59. for i in range(len(time_list)) :
  60. time_list[i] = int(time_list[i])
  61. return time_list
  62. def delta_time():
  63. x = get_time()
  64. time.sleep(INTERVAL)
  65. y = get_time()
  66. for i in range(len(x)):
  67. y[i]-=x[i]
  68. return y
  69. def get_cpu():
  70. t = delta_time()
  71. st = sum(t)
  72. if st == 0:
  73. st = 1
  74. result = 100-(t[len(t)-1]*100.00/st)
  75. return round(result, 1)
  76. def liuliang():
  77. NET_IN = 0
  78. NET_OUT = 0
  79. with open('/proc/net/dev') as f:
  80. for line in f.readlines():
  81. netinfo = re.findall('([^\s]+):[\s]{0,}(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)', line)
  82. if netinfo:
  83. if netinfo[0][0] == 'lo' or 'tun' in netinfo[0][0] \
  84. or 'docker' in netinfo[0][0] or 'veth' in netinfo[0][0] \
  85. or 'br-' in netinfo[0][0] or 'vmbr' in netinfo[0][0] \
  86. or 'vnet' in netinfo[0][0] or 'kube' in netinfo[0][0] \
  87. or netinfo[0][1]=='0' or netinfo[0][9]=='0':
  88. continue
  89. else:
  90. NET_IN += int(netinfo[0][1])
  91. NET_OUT += int(netinfo[0][9])
  92. return NET_IN, NET_OUT
  93. def tupd():
  94. '''
  95. tcp, udp, process, thread count: for view ddcc attack , then send warning
  96. :return:
  97. '''
  98. s = subprocess.check_output("ss -t|wc -l", shell=True)
  99. t = int(s[:-1])-1
  100. s = subprocess.check_output("ss -u|wc -l", shell=True)
  101. u = int(s[:-1])-1
  102. s = subprocess.check_output("ps -ef|wc -l", shell=True)
  103. p = int(s[:-1])-2
  104. s = subprocess.check_output("ps -eLf|wc -l", shell=True)
  105. d = int(s[:-1])-2
  106. return t,u,p,d
  107. def get_network(ip_version):
  108. if(ip_version == 4):
  109. HOST = "ipv4.google.com"
  110. elif(ip_version == 6):
  111. HOST = "ipv6.google.com"
  112. try:
  113. socket.create_connection((HOST, 80), 2).close()
  114. return True
  115. except:
  116. return False
  117. lostRate = {
  118. '10010': 0.0,
  119. '189': 0.0,
  120. '10086': 0.0
  121. }
  122. pingTime = {
  123. '10010': 0,
  124. '189': 0,
  125. '10086': 0
  126. }
  127. netSpeed = {
  128. 'netrx': 0.0,
  129. 'nettx': 0.0,
  130. 'clock': 0.0,
  131. 'diff': 0.0,
  132. 'avgrx': 0,
  133. 'avgtx': 0
  134. }
  135. diskIO = {
  136. 'read': 0,
  137. 'write': 0
  138. }
  139. def _ping_thread(host, mark, port):
  140. lostPacket = 0
  141. packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
  142. IP = host
  143. if host.count(':') < 1: # if not plain ipv6 address, means ipv4 address or hostname
  144. try:
  145. if PROBE_PROTOCOL_PREFER == 'ipv4':
  146. IP = socket.getaddrinfo(host, None, socket.AF_INET)[0][4][0]
  147. else:
  148. IP = socket.getaddrinfo(host, None, socket.AF_INET6)[0][4][0]
  149. except Exception:
  150. pass
  151. while True:
  152. if packet_queue.full():
  153. if packet_queue.get() == 0:
  154. lostPacket -= 1
  155. try:
  156. b = timeit.default_timer()
  157. socket.create_connection((IP, port), timeout=1).close()
  158. pingTime[mark] = int((timeit.default_timer() - b) * 1000)
  159. packet_queue.put(1)
  160. except socket.error as error:
  161. if error.errno == errno.ECONNREFUSED:
  162. pingTime[mark] = int((timeit.default_timer() - b) * 1000)
  163. packet_queue.put(1)
  164. #elif error.errno == errno.ETIMEDOUT:
  165. else:
  166. lostPacket += 1
  167. packet_queue.put(0)
  168. if packet_queue.qsize() > 30:
  169. lostRate[mark] = float(lostPacket) / packet_queue.qsize()
  170. time.sleep(INTERVAL)
  171. def _net_speed():
  172. while True:
  173. with open("/proc/net/dev", "r") as f:
  174. net_dev = f.readlines()
  175. avgrx = 0
  176. avgtx = 0
  177. for dev in net_dev[2:]:
  178. dev = dev.split(':')
  179. if "lo" in dev[0] or "tun" in dev[0] \
  180. or "docker" in dev[0] or "veth" in dev[0] \
  181. or "br-" in dev[0] or "vmbr" in dev[0] \
  182. or "vnet" in dev[0] or "kube" in dev[0]:
  183. continue
  184. dev = dev[1].split()
  185. avgrx += int(dev[0])
  186. avgtx += int(dev[8])
  187. now_clock = time.time()
  188. netSpeed["diff"] = now_clock - netSpeed["clock"]
  189. netSpeed["clock"] = now_clock
  190. netSpeed["netrx"] = int((avgrx - netSpeed["avgrx"]) / netSpeed["diff"])
  191. netSpeed["nettx"] = int((avgtx - netSpeed["avgtx"]) / netSpeed["diff"])
  192. netSpeed["avgrx"] = avgrx
  193. netSpeed["avgtx"] = avgtx
  194. time.sleep(INTERVAL)
  195. def _disk_io():
  196. '''
  197. good luck for opensource! by: cpp.la
  198. 磁盘IO:因为IOPS原因,SSD和HDD、包括RAID卡,ZFS等阵列技术。IO对性能的影响还需要结合自身服务器情况来判断。
  199. 比如我这里是机械硬盘,大量做随机小文件读写,那么很低的读写也就能造成硬盘长时间的等待。
  200. 如果这里做连续性IO,那么普通机械硬盘写入到100Mb/s,那么也能造成硬盘长时间的等待。
  201. 磁盘读写有误差:4k,8k ,https://stackoverflow.com/questions/34413926/psutil-vs-dd-monitoring-disk-i-o
  202. :return:
  203. '''
  204. while True:
  205. # pre pid snapshot
  206. snapshot_first = {}
  207. # next pid snapshot
  208. snapshot_second = {}
  209. # read count snapshot
  210. snapshot_read = 0
  211. # write count snapshot
  212. snapshot_write = 0
  213. # process snapshot
  214. pid_snapshot = [str(i) for i in os.listdir("/proc") if i.isdigit() is True]
  215. for pid in pid_snapshot:
  216. try:
  217. with open("/proc/{}/io".format(pid)) as f:
  218. pid_io = {}
  219. for line in f.readlines():
  220. if "read_bytes" in line:
  221. pid_io["read"] = int(line.split("read_bytes:")[-1].strip())
  222. elif "write_bytes" in line and "cancelled_write_bytes" not in line:
  223. pid_io["write"] = int(line.split("write_bytes:")[-1].strip())
  224. pid_io["name"] = open("/proc/{}/comm".format(pid), "r").read().strip()
  225. snapshot_first[pid] = pid_io
  226. except:
  227. if pid in snapshot_first:
  228. snapshot_first.pop(pid)
  229. time.sleep(INTERVAL)
  230. for pid in pid_snapshot:
  231. try:
  232. with open("/proc/{}/io".format(pid)) as f:
  233. pid_io = {}
  234. for line in f.readlines():
  235. if "read_bytes" in line:
  236. pid_io["read"] = int(line.split("read_bytes:")[-1].strip())
  237. elif "write_bytes" in line and "cancelled_write_bytes" not in line:
  238. pid_io["write"] = int(line.split("write_bytes:")[-1].strip())
  239. pid_io["name"] = open("/proc/{}/comm".format(pid), "r").read().strip()
  240. snapshot_second[pid] = pid_io
  241. except:
  242. if pid in snapshot_first:
  243. snapshot_first.pop(pid)
  244. if pid in snapshot_second:
  245. snapshot_second.pop(pid)
  246. for k, v in snapshot_first.items():
  247. if snapshot_first[k]["name"] == snapshot_second[k]["name"] and snapshot_first[k]["name"] != "bash":
  248. snapshot_read += (snapshot_second[k]["read"] - snapshot_first[k]["read"])
  249. snapshot_write += (snapshot_second[k]["write"] - snapshot_first[k]["write"])
  250. diskIO["read"] = snapshot_read
  251. diskIO["write"] = snapshot_write
  252. def get_realtime_data():
  253. '''
  254. real time get system data
  255. :return:
  256. '''
  257. t1 = threading.Thread(
  258. target=_ping_thread,
  259. kwargs={
  260. 'host': CU,
  261. 'mark': '10010',
  262. 'port': PROBEPORT
  263. }
  264. )
  265. t2 = threading.Thread(
  266. target=_ping_thread,
  267. kwargs={
  268. 'host': CT,
  269. 'mark': '189',
  270. 'port': PROBEPORT
  271. }
  272. )
  273. t3 = threading.Thread(
  274. target=_ping_thread,
  275. kwargs={
  276. 'host': CM,
  277. 'mark': '10086',
  278. 'port': PROBEPORT
  279. }
  280. )
  281. t4 = threading.Thread(
  282. target=_net_speed,
  283. )
  284. t5 = threading.Thread(
  285. target=_disk_io,
  286. )
  287. for ti in [t1, t2, t3, t4, t5]:
  288. ti.daemon = True
  289. ti.start()
  290. def byte_str(object):
  291. '''
  292. bytes to str, str to bytes
  293. :param object:
  294. :return:
  295. '''
  296. if isinstance(object, str):
  297. return object.encode(encoding="utf-8")
  298. elif isinstance(object, bytes):
  299. return bytes.decode(object)
  300. else:
  301. print(type(object))
  302. if __name__ == '__main__':
  303. for argc in sys.argv:
  304. if 'SERVER' in argc:
  305. SERVER = argc.split('SERVER=')[-1]
  306. elif 'PORT' in argc:
  307. PORT = int(argc.split('PORT=')[-1])
  308. elif 'USER' in argc:
  309. USER = argc.split('USER=')[-1]
  310. elif 'PASSWORD' in argc:
  311. PASSWORD = argc.split('PASSWORD=')[-1]
  312. elif 'INTERVAL' in argc:
  313. INTERVAL = int(argc.split('INTERVAL=')[-1])
  314. socket.setdefaulttimeout(30)
  315. get_realtime_data()
  316. while True:
  317. try:
  318. print("Connecting...")
  319. s = socket.create_connection((SERVER, PORT))
  320. data = byte_str(s.recv(1024))
  321. if data.find("Authentication required") > -1:
  322. s.send(byte_str(USER + ':' + PASSWORD + '\n'))
  323. data = byte_str(s.recv(1024))
  324. if data.find("Authentication successful") < 0:
  325. print(data)
  326. raise socket.error
  327. else:
  328. print(data)
  329. raise socket.error
  330. print(data)
  331. if data.find("You are connecting via") < 0:
  332. data = byte_str(s.recv(1024))
  333. print(data)
  334. timer = 0
  335. check_ip = 0
  336. if data.find("IPv4") > -1:
  337. check_ip = 6
  338. elif data.find("IPv6") > -1:
  339. check_ip = 4
  340. else:
  341. print(data)
  342. raise socket.error
  343. while True:
  344. CPU = get_cpu()
  345. NET_IN, NET_OUT = liuliang()
  346. Uptime = get_uptime()
  347. Load_1, Load_5, Load_15 = os.getloadavg()
  348. MemoryTotal, MemoryUsed, SwapTotal, SwapFree = get_memory()
  349. HDDTotal, HDDUsed = get_hdd()
  350. array = {}
  351. if not timer:
  352. array['online' + str(check_ip)] = get_network(check_ip)
  353. timer = 10
  354. else:
  355. timer -= 1*INTERVAL
  356. array['uptime'] = Uptime
  357. array['load_1'] = Load_1
  358. array['load_5'] = Load_5
  359. array['load_15'] = Load_15
  360. array['memory_total'] = MemoryTotal
  361. array['memory_used'] = MemoryUsed
  362. array['swap_total'] = SwapTotal
  363. array['swap_used'] = SwapTotal - SwapFree
  364. array['hdd_total'] = HDDTotal
  365. array['hdd_used'] = HDDUsed
  366. array['cpu'] = CPU
  367. array['network_rx'] = netSpeed.get("netrx")
  368. array['network_tx'] = netSpeed.get("nettx")
  369. array['network_in'] = NET_IN
  370. array['network_out'] = NET_OUT
  371. # todo:兼容旧版本,下个版本删除ip_status
  372. array['ip_status'] = True
  373. array['ping_10010'] = lostRate.get('10010') * 100
  374. array['ping_189'] = lostRate.get('189') * 100
  375. array['ping_10086'] = lostRate.get('10086') * 100
  376. array['time_10010'] = pingTime.get('10010')
  377. array['time_189'] = pingTime.get('189')
  378. array['time_10086'] = pingTime.get('10086')
  379. array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
  380. array['io_read'] = diskIO.get("read")
  381. array['io_write'] = diskIO.get("write")
  382. s.send(byte_str("update " + json.dumps(array) + "\n"))
  383. except KeyboardInterrupt:
  384. raise
  385. except socket.error:
  386. print("Disconnected...")
  387. if 's' in locals().keys():
  388. del s
  389. time.sleep(3)
  390. except Exception as e:
  391. print("Caught Exception:", e)
  392. if 's' in locals().keys():
  393. del s
  394. time.sleep(3)