1
0

client-psutil.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. #!/usr/bin/env python3
  2. # coding: utf-8
  3. # Update by : https://github.com/cppla/ServerStatus, Update date: 20220530
  4. # 依赖于psutil跨平台库
  5. # 版本:1.0.3, 支持Python版本:2.7 to 3.10
  6. # 支持操作系统: Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures
  7. # 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。
  8. SERVER = "127.0.0.1"
  9. USER = "s01"
  10. PASSWORD = "USER_DEFAULT_PASSWORD"
  11. PORT = 35601
  12. CU = "cu.tz.cloudcpp.com"
  13. CT = "ct.tz.cloudcpp.com"
  14. CM = "cm.tz.cloudcpp.com"
  15. PROBEPORT = 80
  16. PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6
  17. PING_PACKET_HISTORY_LEN = 100
  18. INTERVAL = 1
  19. import socket
  20. import time
  21. import timeit
  22. import os
  23. import sys
  24. import json
  25. import errno
  26. import psutil
  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. return int(time.time() - psutil.boot_time())
  34. def get_memory():
  35. Mem = psutil.virtual_memory()
  36. return int(Mem.total / 1024.0), int(Mem.used / 1024.0)
  37. def get_swap():
  38. Mem = psutil.swap_memory()
  39. return int(Mem.total/1024.0), int(Mem.used/1024.0)
  40. def get_hdd():
  41. valid_fs = [ "ext4", "ext3", "ext2", "reiserfs", "jfs", "btrfs", "fuseblk", "zfs", "simfs", "ntfs", "fat32", "exfat", "xfs" ]
  42. disks = dict()
  43. size = 0
  44. used = 0
  45. for disk in psutil.disk_partitions():
  46. if not disk.device in disks and disk.fstype.lower() in valid_fs:
  47. disks[disk.device] = disk.mountpoint
  48. for disk in disks.values():
  49. usage = psutil.disk_usage(disk)
  50. size += usage.total
  51. used += usage.used
  52. return int(size/1024.0/1024.0), int(used/1024.0/1024.0)
  53. def get_cpu():
  54. return psutil.cpu_percent(interval=INTERVAL)
  55. def liuliang():
  56. NET_IN = 0
  57. NET_OUT = 0
  58. net = psutil.net_io_counters(pernic=True)
  59. for k, v in net.items():
  60. if 'lo' in k or 'tun' in k \
  61. or 'docker' in k or 'veth' in k \
  62. or 'br-' in k or 'vmbr' in k \
  63. or 'vnet' in k or 'kube' in k:
  64. continue
  65. else:
  66. NET_IN += v[1]
  67. NET_OUT += v[0]
  68. return NET_IN, NET_OUT
  69. def tupd():
  70. '''
  71. tcp, udp, process, thread count: for view ddcc attack , then send warning
  72. :return:
  73. '''
  74. try:
  75. if sys.platform.startswith("linux") is True:
  76. t = int(os.popen('ss -t|wc -l').read()[:-1])-1
  77. u = int(os.popen('ss -u|wc -l').read()[:-1])-1
  78. p = int(os.popen('ps -ef|wc -l').read()[:-1])-2
  79. d = int(os.popen('ps -eLf|wc -l').read()[:-1])-2
  80. elif sys.platform.startswith("win") is True:
  81. t = int(os.popen('netstat -an|find "TCP" /c').read()[:-1])-1
  82. u = int(os.popen('netstat -an|find "UDP" /c').read()[:-1])-1
  83. p = len(psutil.pids())
  84. d = 0
  85. # cpu is high, default: 0
  86. # d = sum([psutil.Process(k).num_threads() for k in [x for x in psutil.pids()]])
  87. else:
  88. t,u,p,d = 0,0,0,0
  89. return t,u,p,d
  90. except:
  91. return 0,0,0,0
  92. def get_network(ip_version):
  93. if(ip_version == 4):
  94. HOST = "ipv4.google.com"
  95. elif(ip_version == 6):
  96. HOST = "ipv6.google.com"
  97. try:
  98. socket.create_connection((HOST, 80), 2).close()
  99. return True
  100. except:
  101. return False
  102. lostRate = {
  103. '10010': 0.0,
  104. '189': 0.0,
  105. '10086': 0.0
  106. }
  107. pingTime = {
  108. '10010': 0,
  109. '189': 0,
  110. '10086': 0
  111. }
  112. netSpeed = {
  113. 'netrx': 0.0,
  114. 'nettx': 0.0,
  115. 'clock': 0.0,
  116. 'diff': 0.0,
  117. 'avgrx': 0,
  118. 'avgtx': 0
  119. }
  120. diskIO = {
  121. 'read': 0,
  122. 'write': 0
  123. }
  124. def _ping_thread(host, mark, port):
  125. lostPacket = 0
  126. packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
  127. IP = host
  128. if host.count(':') < 1: # if not plain ipv6 address, means ipv4 address or hostname
  129. try:
  130. if PROBE_PROTOCOL_PREFER == 'ipv4':
  131. IP = socket.getaddrinfo(host, None, socket.AF_INET)[0][4][0]
  132. else:
  133. IP = socket.getaddrinfo(host, None, socket.AF_INET6)[0][4][0]
  134. except Exception:
  135. pass
  136. while True:
  137. if packet_queue.full():
  138. if packet_queue.get() == 0:
  139. lostPacket -= 1
  140. try:
  141. b = timeit.default_timer()
  142. socket.create_connection((IP, port), timeout=1).close()
  143. pingTime[mark] = int((timeit.default_timer() - b) * 1000)
  144. packet_queue.put(1)
  145. except socket.error as error:
  146. if error.errno == errno.ECONNREFUSED:
  147. pingTime[mark] = int((timeit.default_timer() - b) * 1000)
  148. packet_queue.put(1)
  149. #elif error.errno == errno.ETIMEDOUT:
  150. else:
  151. lostPacket += 1
  152. packet_queue.put(0)
  153. if packet_queue.qsize() > 30:
  154. lostRate[mark] = float(lostPacket) / packet_queue.qsize()
  155. time.sleep(INTERVAL)
  156. def _net_speed():
  157. while True:
  158. avgrx = 0
  159. avgtx = 0
  160. for name, stats in psutil.net_io_counters(pernic=True).items():
  161. if "lo" in name or "tun" in name \
  162. or "docker" in name or "veth" in name \
  163. or "br-" in name or "vmbr" in name \
  164. or "vnet" in name or "kube" in name:
  165. continue
  166. avgrx += stats.bytes_recv
  167. avgtx += stats.bytes_sent
  168. now_clock = time.time()
  169. netSpeed["diff"] = now_clock - netSpeed["clock"]
  170. netSpeed["clock"] = now_clock
  171. netSpeed["netrx"] = int((avgrx - netSpeed["avgrx"]) / netSpeed["diff"])
  172. netSpeed["nettx"] = int((avgtx - netSpeed["avgtx"]) / netSpeed["diff"])
  173. netSpeed["avgrx"] = avgrx
  174. netSpeed["avgtx"] = avgtx
  175. time.sleep(INTERVAL)
  176. def _disk_io():
  177. """
  178. the code is by: https://github.com/giampaolo/psutil/blob/master/scripts/iotop.py
  179. good luck for opensource! modify: cpp.la
  180. Calculate IO usage by comparing IO statics before and
  181. after the interval.
  182. Return a tuple including all currently running processes
  183. sorted by IO activity and total disks I/O activity.
  184. 磁盘IO:因为IOPS原因,SSD和HDD、包括RAID卡,ZFS等。IO对性能的影响还需要结合自身服务器情况来判断。
  185. 比如我这里是机械硬盘,大量做随机小文件读写,那么很低的读写也就能造成硬盘长时间的等待。
  186. 如果这里做连续性IO,那么普通机械硬盘写入到100Mb/s,那么也能造成硬盘长时间的等待。
  187. 磁盘读写有误差:4k,8k ,https://stackoverflow.com/questions/34413926/psutil-vs-dd-monitoring-disk-i-o
  188. """
  189. while True:
  190. # first get a list of all processes and disk io counters
  191. procs = [p for p in psutil.process_iter()]
  192. for p in procs[:]:
  193. try:
  194. p._before = p.io_counters()
  195. except psutil.Error:
  196. procs.remove(p)
  197. continue
  198. disks_before = psutil.disk_io_counters()
  199. # sleep some time, only when INTERVAL==1 , io read/write per_sec.
  200. # when INTERVAL > 1, io read/write per_INTERVAL
  201. time.sleep(INTERVAL)
  202. # then retrieve the same info again
  203. for p in procs[:]:
  204. with p.oneshot():
  205. try:
  206. p._after = p.io_counters()
  207. p._cmdline = ' '.join(p.cmdline())
  208. if not p._cmdline:
  209. p._cmdline = p.name()
  210. p._username = p.username()
  211. except (psutil.NoSuchProcess, psutil.ZombieProcess):
  212. procs.remove(p)
  213. disks_after = psutil.disk_io_counters()
  214. # finally calculate results by comparing data before and
  215. # after the interval
  216. for p in procs:
  217. p._read_per_sec = p._after.read_bytes - p._before.read_bytes
  218. p._write_per_sec = p._after.write_bytes - p._before.write_bytes
  219. p._total = p._read_per_sec + p._write_per_sec
  220. diskIO["read"] = disks_after.read_bytes - disks_before.read_bytes
  221. diskIO["write"] = disks_after.write_bytes - disks_before.write_bytes
  222. def get_realtime_data():
  223. '''
  224. real time get system data
  225. :return:
  226. '''
  227. t1 = threading.Thread(
  228. target=_ping_thread,
  229. kwargs={
  230. 'host': CU,
  231. 'mark': '10010',
  232. 'port': PROBEPORT
  233. }
  234. )
  235. t2 = threading.Thread(
  236. target=_ping_thread,
  237. kwargs={
  238. 'host': CT,
  239. 'mark': '189',
  240. 'port': PROBEPORT
  241. }
  242. )
  243. t3 = threading.Thread(
  244. target=_ping_thread,
  245. kwargs={
  246. 'host': CM,
  247. 'mark': '10086',
  248. 'port': PROBEPORT
  249. }
  250. )
  251. t4 = threading.Thread(
  252. target=_net_speed,
  253. )
  254. t5 = threading.Thread(
  255. target=_disk_io,
  256. )
  257. for ti in [t1, t2, t3, t4, t5]:
  258. ti.daemon = True
  259. ti.start()
  260. def byte_str(object):
  261. '''
  262. bytes to str, str to bytes
  263. :param object:
  264. :return:
  265. '''
  266. if isinstance(object, str):
  267. return object.encode(encoding="utf-8")
  268. elif isinstance(object, bytes):
  269. return bytes.decode(object)
  270. else:
  271. print(type(object))
  272. if __name__ == '__main__':
  273. for argc in sys.argv:
  274. if 'SERVER' in argc:
  275. SERVER = argc.split('SERVER=')[-1]
  276. elif 'PORT' in argc:
  277. PORT = int(argc.split('PORT=')[-1])
  278. elif 'USER' in argc:
  279. USER = argc.split('USER=')[-1]
  280. elif 'PASSWORD' in argc:
  281. PASSWORD = argc.split('PASSWORD=')[-1]
  282. elif 'INTERVAL' in argc:
  283. INTERVAL = int(argc.split('INTERVAL=')[-1])
  284. socket.setdefaulttimeout(30)
  285. get_realtime_data()
  286. while 1:
  287. try:
  288. print("Connecting...")
  289. s = socket.create_connection((SERVER, PORT))
  290. data = byte_str(s.recv(1024))
  291. if data.find("Authentication required") > -1:
  292. s.send(byte_str(USER + ':' + PASSWORD + '\n'))
  293. data = byte_str(s.recv(1024))
  294. if data.find("Authentication successful") < 0:
  295. print(data)
  296. raise socket.error
  297. else:
  298. print(data)
  299. raise socket.error
  300. print(data)
  301. if data.find("You are connecting via") < 0:
  302. data = byte_str(s.recv(1024))
  303. print(data)
  304. timer = 0
  305. check_ip = 0
  306. if data.find("IPv4") > -1:
  307. check_ip = 6
  308. elif data.find("IPv6") > -1:
  309. check_ip = 4
  310. else:
  311. print(data)
  312. raise socket.error
  313. while 1:
  314. CPU = get_cpu()
  315. NET_IN, NET_OUT = liuliang()
  316. Uptime = get_uptime()
  317. Load_1, Load_5, Load_15 = os.getloadavg() if 'linux' in sys.platform else (0.0, 0.0, 0.0)
  318. MemoryTotal, MemoryUsed = get_memory()
  319. SwapTotal, SwapUsed = get_swap()
  320. HDDTotal, HDDUsed = get_hdd()
  321. array = {}
  322. if not timer:
  323. array['online' + str(check_ip)] = get_network(check_ip)
  324. timer = 10
  325. else:
  326. timer -= 1*INTERVAL
  327. array['uptime'] = Uptime
  328. array['load_1'] = Load_1
  329. array['load_5'] = Load_5
  330. array['load_15'] = Load_15
  331. array['memory_total'] = MemoryTotal
  332. array['memory_used'] = MemoryUsed
  333. array['swap_total'] = SwapTotal
  334. array['swap_used'] = SwapUsed
  335. array['hdd_total'] = HDDTotal
  336. array['hdd_used'] = HDDUsed
  337. array['cpu'] = CPU
  338. array['network_rx'] = netSpeed.get("netrx")
  339. array['network_tx'] = netSpeed.get("nettx")
  340. array['network_in'] = NET_IN
  341. array['network_out'] = NET_OUT
  342. # todo:兼容旧版本,下个版本删除ip_status
  343. array['ip_status'] = True
  344. array['ping_10010'] = lostRate.get('10010') * 100
  345. array['ping_189'] = lostRate.get('189') * 100
  346. array['ping_10086'] = lostRate.get('10086') * 100
  347. array['time_10010'] = pingTime.get('10010')
  348. array['time_189'] = pingTime.get('189')
  349. array['time_10086'] = pingTime.get('10086')
  350. array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
  351. array['io_read'] = diskIO.get("read")
  352. array['io_write'] = diskIO.get("write")
  353. s.send(byte_str("update " + json.dumps(array) + "\n"))
  354. except KeyboardInterrupt:
  355. raise
  356. except socket.error:
  357. print("Disconnected...")
  358. if 's' in locals().keys():
  359. del s
  360. time.sleep(3)
  361. except Exception as e:
  362. print("Caught Exception:", e)
  363. if 's' in locals().keys():
  364. del s
  365. time.sleep(3)