├── requirements.txt ├── LICENSE ├── systemInfo.py └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | WMI==1.5.1 2 | cachelib==0.1.1 3 | psutil==5.7.2 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Pure-Peace 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /systemInfo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | @name: 系统信息 / SystemInfo 4 | @author: PurePeace 5 | @time: 2020年8月17日 6 | @version: 0.1 7 | ''' 8 | 9 | from typing import List, Dict, Any 10 | 11 | import os 12 | import time 13 | import psutil 14 | import platform 15 | import hashlib 16 | import re 17 | import sys 18 | 19 | 20 | from cachelib import SimpleCache 21 | cache = SimpleCache() 22 | 23 | 24 | UNIX: bool = os.name == 'posix' 25 | SYS: str = platform.system() 26 | 27 | 28 | class CpuConstants: 29 | def __init__(self): 30 | ''' 31 | 初始化CPU常量(多平台) 32 | 33 | Returns 34 | ------- 35 | self. 36 | 37 | ''' 38 | self.WMI = None 39 | self.initialed: bool = False 40 | self.cpuList: list = [] # windows only 41 | 42 | self.cpuCount: int = 0 # 物理cpu数量 43 | self.cpuCore: int = 0 # cpu物理核心数 44 | self.cpuThreads: int = 0 # cpu逻辑核心数 45 | self.cpuName: str = '' # cpu型号 46 | 47 | self.Update(True) 48 | 49 | 50 | def Update(self, update: bool = False) -> None: 51 | ''' 52 | 更新cpu数据 53 | 54 | Returns 55 | ------- 56 | None. 57 | 58 | ''' 59 | if UNIX: self.GetCpuConstantsUnix(update) 60 | else: self.GetCpuConstantsWindows(update) 61 | 62 | self.initialed: bool = True 63 | 64 | 65 | @property 66 | def getDict(self) -> Dict[int, str]: 67 | ''' 68 | 以字典格式获取当前cpu常量 69 | 70 | Returns 71 | ------- 72 | Dict[int, str] 73 | DESCRIPTION. 74 | 75 | ''' 76 | if not self.initialed: self.Update() 77 | return { 78 | 'cpu_count': self.cpuCount, 79 | 'cpu_name': self.cpuName, 80 | 'cpu_core': self.cpuCore, 81 | 'cpu_threads': self.cpuThreads 82 | } 83 | 84 | 85 | def GetCpuConstantsUnix(self, update: bool = False) -> None: 86 | ''' 87 | 获取unix下的cpu信息 88 | 89 | Parameters 90 | ---------- 91 | update : bool, optional 92 | DESCRIPTION. The default is False. 93 | 94 | Returns 95 | ------- 96 | None 97 | DESCRIPTION. 98 | 99 | ''' 100 | if update or not self.initialed: 101 | ids: list = re.findall("physical id.+", readFile('/proc/cpuinfo')) 102 | 103 | # 物理cpu个数 104 | self.cpuCount: int = len(set(ids)) 105 | 106 | # cpu型号(名称) 107 | self.cpuName: str = self.getCpuTypeUnix() 108 | 109 | 110 | self.GetCpuConstantsBoth() 111 | 112 | 113 | def InitWmi(self) -> None: 114 | ''' 115 | 初始化wmi(for windows) 116 | 117 | Returns 118 | ------- 119 | None 120 | DESCRIPTION. 121 | 122 | ''' 123 | import wmi 124 | self.WMI = wmi.WMI() 125 | 126 | 127 | def GetCpuConstantsBoth(self, update: bool = False) -> None: 128 | ''' 129 | 获取多平台共用的cpu信息 130 | 131 | Parameters 132 | ---------- 133 | update : bool, optional 134 | 强制更新数据. The default is False. 135 | 136 | Returns 137 | ------- 138 | None 139 | DESCRIPTION. 140 | 141 | ''' 142 | if update or not self.initialed: 143 | 144 | # cpu逻辑核心数 145 | self.cpuThreads: int = psutil.cpu_count() 146 | 147 | # cpu物理核心数 148 | self.cpuCore: int = psutil.cpu_count(logical=False) 149 | 150 | 151 | def GetCpuConstantsWindows(self, update: bool = False) -> None: 152 | ''' 153 | 获取windows平台的cpu信息 154 | 155 | Parameters 156 | ---------- 157 | update : bool, optional 158 | 强制更新数据. The default is False. 159 | 160 | Returns 161 | ------- 162 | None 163 | DESCRIPTION. 164 | 165 | ''' 166 | if update or not self.initialed: 167 | 168 | # 初始化wmi 169 | if self.WMI == None: self.InitWmi() 170 | 171 | # cpu列表 172 | self.cpuList: list = self.WMI.Win32_Processor() 173 | 174 | # 物理cpu个数 175 | self.cpuCount: int = len(self.cpuList) 176 | 177 | # cpu型号(名称) 178 | self.cpuName: str = self.cpuList[0].Name 179 | 180 | 181 | self.GetCpuConstantsBoth() 182 | 183 | 184 | @staticmethod 185 | def getCpuTypeUnix() -> str: 186 | ''' 187 | 获取CPU型号(unix) 188 | 189 | Returns 190 | ------- 191 | str 192 | CPU型号. 193 | 194 | ''' 195 | cpuinfo: str = readFile('/proc/cpuinfo') 196 | rep: str = 'model\s+name\s+:\s+(.+)' 197 | tmp = re.search(rep,cpuinfo,re.I) 198 | cpuType: str = '' 199 | if tmp: 200 | cpuType: str = tmp.groups()[0] 201 | else: 202 | cpuinfo = ExecShellUnix('LANG="en_US.UTF-8" && lscpu')[0] 203 | rep = 'Model\s+name:\s+(.+)' 204 | tmp = re.search(rep,cpuinfo,re.I) 205 | if tmp: cpuType = tmp.groups()[0] 206 | return cpuType 207 | 208 | 209 | def GetCpuInfo(interval: int = 1) -> Dict[str, Any]: 210 | ''' 211 | 获取CPU信息 212 | 213 | Parameters 214 | ---------- 215 | interval : int, optional 216 | DESCRIPTION. The default is 1. 217 | 218 | Returns 219 | ------- 220 | Dict[float, list, dict] 221 | DESCRIPTION. 222 | 223 | ''' 224 | time.sleep(0.5) 225 | 226 | 227 | # cpu总使用率 228 | used: float = psutil.cpu_percent(interval) 229 | 230 | # 每个逻辑cpu使用率 231 | usedList: List[float] = psutil.cpu_percent(percpu=True) 232 | 233 | 234 | return {'used': used, 'used_list': usedList, **cpuConstants.getDict} 235 | 236 | 237 | def readFile(filename: str) -> str: 238 | ''' 239 | 读取文件内容 240 | 241 | Parameters 242 | ---------- 243 | filename : str 244 | 文件名. 245 | 246 | Returns 247 | ------- 248 | str 249 | 文件内容. 250 | 251 | ''' 252 | try: 253 | with open(filename, 'r', encoding='utf-8') as file: return file.read() 254 | except: 255 | pass 256 | 257 | return '' 258 | 259 | 260 | def GetLoadAverage() -> dict: 261 | ''' 262 | 获取服务器负载状态(多平台) 263 | 264 | Returns 265 | ------- 266 | dict 267 | DESCRIPTION. 268 | 269 | ''' 270 | try: c: list = os.getloadavg() 271 | except: c: list = [0,0,0] 272 | data: dict = {i: c[idx] for idx, i in enumerate(('one', 'five', 'fifteen'))} 273 | data['max'] = psutil.cpu_count() * 2 274 | data['limit'] = data['max'] 275 | data['safe'] = data['max'] * 0.75 276 | return data 277 | 278 | 279 | def GetMemInfo() -> dict: 280 | ''' 281 | 获取内存信息(多平台) 282 | 283 | Returns 284 | ------- 285 | dict 286 | DESCRIPTION. 287 | 288 | ''' 289 | if UNIX: return GetMemInfoUnix() 290 | return GetMemInfoWindows() 291 | 292 | 293 | def GetMemInfoUnix() -> Dict[str, int]: 294 | ''' 295 | 获取内存信息(unix) 296 | 297 | Returns 298 | ------- 299 | dict 300 | DESCRIPTION. 301 | 302 | ''' 303 | mem = psutil.virtual_memory() 304 | memInfo: dict = { 305 | 'memTotal': ToSizeInt(mem.total, 'MB'), 306 | 'memFree': ToSizeInt(mem.free, 'MB'), 307 | 'memBuffers': ToSizeInt(mem.buffers, 'MB'), 308 | 'memCached': ToSizeInt(mem.cached, 'MB'), 309 | } 310 | memInfo['memRealUsed'] = \ 311 | memInfo['memTotal'] - \ 312 | memInfo['memFree'] - \ 313 | memInfo['memBuffers'] - \ 314 | memInfo['memCached'] 315 | 316 | memInfo['memUsedPercent'] = memInfo['memRealUsed'] / memInfo['memTotal'] * 100 317 | 318 | return memInfo 319 | 320 | 321 | def GetMemInfoWindows() -> dict: 322 | ''' 323 | 获取内存信息(windows) 324 | 325 | Returns 326 | ------- 327 | dict 328 | DESCRIPTION. 329 | 330 | ''' 331 | mem = psutil.virtual_memory() 332 | memInfo: dict = { 333 | 'memTotal': ToSizeInt(mem.total, 'MB'), 334 | 'memFree': ToSizeInt(mem.free, 'MB'), 335 | 'memRealUsed': ToSizeInt(mem.used, 'MB'), 336 | 'menUsedPercent': mem.used / mem.total * 100 337 | } 338 | 339 | return memInfo 340 | 341 | 342 | def ToSizeInt(byte: int, target: str) -> int: 343 | ''' 344 | 将字节大小转换为目标单位的大小 345 | 346 | Parameters 347 | ---------- 348 | byte : int 349 | int格式的字节大小(bytes size) 350 | target : str 351 | 目标单位,str. 352 | 353 | Returns 354 | ------- 355 | int 356 | 转换为目标单位后的字节大小. 357 | 358 | ''' 359 | return int(byte/1024**(('KB','MB','GB','TB').index(target) + 1)) 360 | 361 | 362 | def ToSizeString(byte: int) -> str: 363 | ''' 364 | 获取字节大小字符串 365 | 366 | Parameters 367 | ---------- 368 | byte : int 369 | int格式的字节大小(bytes size). 370 | 371 | Returns 372 | ------- 373 | str 374 | 自动转换后的大小字符串,如:6.90 GB. 375 | 376 | ''' 377 | units: tuple = ('b','KB','MB','GB','TB') 378 | re = lambda: '{:.2f} {}'.format(byte, u) 379 | for u in units: 380 | if byte < 1024: return re() 381 | byte /= 1024 382 | return re() 383 | 384 | 385 | def GetDiskInfo() -> list: 386 | ''' 387 | 获取磁盘信息(多平台) 388 | 389 | Returns 390 | ------- 391 | list 392 | 列表. 393 | 394 | ''' 395 | try: 396 | if UNIX: return GetDiskInfoUnix() 397 | return GetDiskInfoWindows() 398 | except Exception as err: 399 | print('获取磁盘信息异常(unix: {}):'.format(UNIX), err) 400 | return [] 401 | 402 | 403 | def GetDiskInfoWindows() -> list: 404 | ''' 405 | 获取磁盘信息Windows 406 | 407 | Returns 408 | ------- 409 | diskInfo : list 410 | 列表. 411 | 412 | ''' 413 | diskIo: list = psutil.disk_partitions() 414 | diskInfo: list = [] 415 | for disk in diskIo: 416 | tmp: dict = {} 417 | try: 418 | tmp['path'] = disk.mountpoint.replace("\\","/") 419 | usage = psutil.disk_usage(disk.mountpoint) 420 | tmp['size'] = { 421 | 'total': usage.total, 422 | 'used': usage.used, 423 | 'free': usage.free, 424 | 'percent': usage.percent 425 | } 426 | tmp['fstype'] = disk.fstype 427 | tmp['inodes'] = False 428 | diskInfo.append(tmp) 429 | except: 430 | pass 431 | return diskInfo 432 | 433 | 434 | def GetDiskInfoUnix() -> list: 435 | ''' 436 | 获取硬盘分区信息(unix) 437 | 438 | Returns 439 | ------- 440 | list 441 | DESCRIPTION. 442 | 443 | ''' 444 | temp: list = ( 445 | ExecShellUnix("df -h -P|grep '/'|grep -v tmpfs")[0]).split('\n') 446 | tempInodes: list = ( 447 | ExecShellUnix("df -i -P|grep '/'|grep -v tmpfs")[0]).split('\n') 448 | diskInfo: list = [] 449 | n: int = 0 450 | cuts: list = [ 451 | '/mnt/cdrom', 452 | '/boot', 453 | '/boot/efi', 454 | '/dev', 455 | '/dev/shm', 456 | '/run/lock', 457 | '/run', 458 | '/run/shm', 459 | '/run/user' 460 | ] 461 | for tmp in temp: 462 | n += 1 463 | try: 464 | inodes: list = tempInodes[n-1].split() 465 | disk: list = tmp.split() 466 | if len(disk) < 5: continue 467 | if disk[1].find('M') != -1: continue 468 | if disk[1].find('K') != -1: continue 469 | if len(disk[5].split('/')) > 10: continue 470 | if disk[5] in cuts: continue 471 | if disk[5].find('docker') != -1: continue 472 | arr = {} 473 | arr['path'] = disk[5] 474 | tmp1 = [disk[1],disk[2],disk[3],disk[4]] 475 | arr['size'] = tmp1 476 | arr['inodes'] = [inodes[1],inodes[2],inodes[3],inodes[4]] 477 | diskInfo.append(arr) 478 | except Exception as ex: 479 | print('信息获取错误:', str(ex)) 480 | continue 481 | return diskInfo 482 | 483 | 484 | 485 | def md5(strings: str) -> str: 486 | ''' 487 | 生成md5 488 | 489 | Parameters 490 | ---------- 491 | strings : TYPE 492 | 要进行hash处理的字符串 493 | 494 | Returns 495 | ------- 496 | str[32] 497 | hash后的字符串. 498 | 499 | ''' 500 | 501 | m = hashlib.md5() 502 | m.update(strings.encode('utf-8')) 503 | return m.hexdigest() 504 | 505 | 506 | def GetErrorInfo() -> str: 507 | ''' 508 | 获取traceback中的错误 509 | 510 | Returns 511 | ------- 512 | str 513 | DESCRIPTION. 514 | 515 | ''' 516 | import traceback 517 | errorMsg = traceback.format_exc() 518 | return errorMsg 519 | 520 | 521 | def ExecShellUnix(cmdstring: str, shell=True): 522 | ''' 523 | 执行Shell命令(Unix) 524 | 525 | Parameters 526 | ---------- 527 | cmdstring : str 528 | DESCRIPTION. 529 | shell : TYPE, optional 530 | DESCRIPTION. The default is True. 531 | 532 | Returns 533 | ------- 534 | a : TYPE 535 | DESCRIPTION. 536 | e : TYPE 537 | DESCRIPTION. 538 | 539 | ''' 540 | a: str = '' 541 | e: str = '' 542 | import subprocess,tempfile 543 | 544 | try: 545 | rx: str = md5(cmdstring) 546 | succ_f = tempfile.SpooledTemporaryFile( 547 | max_size = 4096, 548 | mode = 'wb+', 549 | suffix = '_succ', 550 | prefix = 'btex_' + rx , 551 | dir = '/dev/shm' 552 | ) 553 | err_f = tempfile.SpooledTemporaryFile( 554 | max_size = 4096, 555 | mode = 'wb+', 556 | suffix = '_err', 557 | prefix = 'btex_' + rx , 558 | dir = '/dev/shm' 559 | ) 560 | sub = subprocess.Popen( 561 | cmdstring, 562 | close_fds = True, 563 | shell = shell, 564 | bufsize = 128, 565 | stdout = succ_f, 566 | stderr = err_f 567 | ) 568 | sub.wait() 569 | err_f.seek(0) 570 | succ_f.seek(0) 571 | a = succ_f.read() 572 | e = err_f.read() 573 | if not err_f.closed: err_f.close() 574 | if not succ_f.closed: succ_f.close() 575 | except Exception as err: 576 | print(err) 577 | try: 578 | if type(a) == bytes: a = a.decode('utf-8') 579 | if type(e) == bytes: e = e.decode('utf-8') 580 | except Exception as err: 581 | print(err) 582 | 583 | return a,e 584 | 585 | 586 | def GetNetWork() -> dict: 587 | ''' 588 | 获取系统网络信息 589 | 590 | Returns 591 | ------- 592 | dict 593 | DESCRIPTION. 594 | 595 | ''' 596 | networkIo: list = [0,0,0,0] 597 | cache_timeout: int = 86400 598 | try: 599 | networkIo = psutil.net_io_counters()[:4] 600 | except: 601 | pass 602 | 603 | otime = cache.get("otime") 604 | if not otime: 605 | otime = time.time() 606 | cache.set('up',networkIo[0],cache_timeout) 607 | cache.set('down',networkIo[1],cache_timeout) 608 | cache.set('otime',otime ,cache_timeout) 609 | 610 | ntime = time.time() 611 | networkInfo: dict = {'up': 0, 'down': 0} 612 | networkInfo['upTotal'] = networkIo[0] 613 | networkInfo['downTotal'] = networkIo[1] 614 | try: 615 | networkInfo['up'] = round( 616 | float(networkIo[0] - cache.get("up")) / 1024 / (ntime - otime), 617 | 2 618 | ) 619 | networkInfo['down'] = round( 620 | float(networkIo[1] - cache.get("down")) / 1024 / (ntime - otime), 621 | 2 622 | ) 623 | except: 624 | pass 625 | 626 | networkInfo['downPackets'] = networkIo[3] 627 | networkInfo['upPackets'] = networkIo[2] 628 | 629 | cache.set('up',networkIo[0],cache_timeout) 630 | cache.set('down',networkIo[1],cache_timeout) 631 | cache.set('otime', time.time(),cache_timeout) 632 | 633 | return networkInfo 634 | 635 | 636 | def GetSystemInfo() -> dict: 637 | systemInfo: dict = {} 638 | systemInfo['cpu'] = GetCpuInfo() 639 | systemInfo['load'] = GetLoadAverage() 640 | systemInfo['mem'] = GetMemInfo() 641 | systemInfo['disk'] = GetDiskInfo() 642 | 643 | return systemInfo 644 | 645 | 646 | 647 | def GetIoReadWrite() -> Dict[str, int]: 648 | ''' 649 | 获取系统IO读写 650 | 651 | Returns 652 | ------- 653 | dict 654 | DESCRIPTION. 655 | 656 | ''' 657 | ioDisk = psutil.disk_io_counters() 658 | ioTotal: dict = {} 659 | ioTotal['write'] = GetIoWrite(ioDisk.write_bytes) 660 | ioTotal['read'] = GetIoRead(ioDisk.read_bytes) 661 | return ioTotal 662 | 663 | 664 | def GetIoWrite(ioWrite: int) -> int: 665 | ''' 666 | 获取IO写 667 | 668 | Parameters 669 | ---------- 670 | ioWrite : TYPE 671 | DESCRIPTION. 672 | 673 | Returns 674 | ------- 675 | int 676 | DESCRIPTION. 677 | 678 | ''' 679 | diskWrite: int = 0 680 | oldWrite: int = cache.get('io_write') 681 | if not oldWrite: 682 | cache.set('io_write', ioWrite) 683 | return diskWrite; 684 | 685 | oldTime: float = cache.get('io_time') 686 | newTime: float = time.time() 687 | if not oldTime: oldTime = newTime 688 | ioEnd: int = (ioWrite - oldWrite) 689 | timeEnd: float = (time.time() - oldTime) 690 | if ioEnd > 0: 691 | if timeEnd < 1: timeEnd = 1 692 | diskWrite = ioEnd / timeEnd 693 | cache.set('io_write',ioWrite) 694 | cache.set('io_time',newTime) 695 | if diskWrite > 0: return int(diskWrite) 696 | return 0 697 | 698 | 699 | def GetIoRead(ioRead): 700 | ''' 701 | 读取IO读 702 | 703 | Parameters 704 | ---------- 705 | ioRead : TYPE 706 | DESCRIPTION. 707 | 708 | Returns 709 | ------- 710 | TYPE 711 | DESCRIPTION. 712 | 713 | ''' 714 | diskRead: int = 0 715 | oldRead: int = cache.get('io_read') 716 | if not oldRead: 717 | cache.set('io_read',ioRead) 718 | return diskRead; 719 | oldTime: float = cache.get('io_time') 720 | newTime: float = time.time() 721 | if not oldTime: oldTime = newTime 722 | ioEnd: int = (ioRead - oldRead) 723 | timeEnd: float = (time.time() - oldTime) 724 | if ioEnd > 0: 725 | if timeEnd < 1: timeEnd = 1; 726 | diskRead = ioEnd / timeEnd; 727 | cache.set('io_read', ioRead) 728 | if diskRead > 0: return int(diskRead) 729 | return 0 730 | 731 | 732 | def GetRegValue(key: str, subkey: str, value: str) -> Any: 733 | ''' 734 | 获取系统注册表信息 735 | 736 | Parameters 737 | ---------- 738 | key : str 739 | 类型. 740 | subkey : str 741 | 路径. 742 | value : str 743 | key. 744 | 745 | Returns 746 | ------- 747 | value : Any 748 | DESCRIPTION. 749 | 750 | ''' 751 | import winreg 752 | key = getattr(winreg, key) 753 | handle = winreg.OpenKey(key, subkey) 754 | (value, type) = winreg.QueryValueEx(handle, value) 755 | return value 756 | 757 | 758 | def GetSystemVersion() -> str: 759 | ''' 760 | 获取操作系统版本(多平台) 761 | 762 | Returns 763 | ------- 764 | str 765 | DESCRIPTION. 766 | 767 | ''' 768 | if UNIX: return GetSystemVersionUnix() 769 | return GetSystemVersionWindows() 770 | 771 | 772 | def GetSystemVersionWindows() -> str: 773 | ''' 774 | 获取操作系统版本(windows) 775 | 776 | Returns 777 | ------- 778 | str 779 | DESCRIPTION. 780 | 781 | ''' 782 | try: 783 | import platform 784 | bit: str = 'x86'; 785 | if 'PROGRAMFILES(X86)' in os.environ: bit = 'x64' 786 | 787 | def get(key: str): 788 | return GetRegValue( 789 | "HKEY_LOCAL_MACHINE", 790 | "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 791 | key 792 | ) 793 | 794 | osName = get('ProductName') 795 | build = get('CurrentBuildNumber') 796 | 797 | version: str = '{} (build {}) {} (Py{})'.format( 798 | osName, build, bit, platform.python_version()) 799 | return version 800 | except Exception as ex: 801 | print('获取系统版本失败,错误:' + str(ex)) 802 | return '未知系统版本.' 803 | 804 | 805 | def GetSystemVersionUnix() -> str: 806 | ''' 807 | 获取系统版本(unix) 808 | 809 | Returns 810 | ------- 811 | str 812 | 系统版本. 813 | 814 | ''' 815 | try: 816 | version: str = readFile('/etc/redhat-release') 817 | if not version: 818 | version = readFile( 819 | '/etc/issue' 820 | ).strip().split("\n")[0].replace('\\n','').replace('\l','').strip() 821 | else: 822 | version = version.replace( 823 | 'release ','' 824 | ).replace('Linux','').replace('(Core)','').strip() 825 | v = sys.version_info 826 | return version + '(Py {}.{}.{})'.format(v.major, v.minor, v.micro) 827 | except Exception as err: 828 | print('获取系统版本失败,错误:', err) 829 | return '未知系统版本.' 830 | 831 | 832 | def GetBootTime() -> dict: 833 | ''' 834 | 获取当前系统启动时间 835 | 836 | Returns 837 | ------- 838 | dict 839 | DESCRIPTION. 840 | 841 | ''' 842 | bootTime: float = psutil.boot_time() 843 | return { 844 | 'timestamp': bootTime, 845 | 'runtime': time.time() - bootTime, 846 | 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) 847 | } 848 | 849 | 850 | def GetCpuConstants() -> dict: 851 | ''' 852 | 获取CPU常量信息 853 | 854 | Parameters 855 | ---------- 856 | cpuConstants : CpuConstants 857 | DESCRIPTION. 858 | 859 | Returns 860 | ------- 861 | dict 862 | DESCRIPTION. 863 | 864 | ''' 865 | return cpuConstants.getDict 866 | 867 | 868 | def GetFullSystemData() -> dict: 869 | ''' 870 | 获取完全的系统信息 871 | 872 | Returns 873 | ------- 874 | dict 875 | DESCRIPTION. 876 | 877 | ''' 878 | systemData: dict = { 879 | **GetSystemInfo(), 880 | 'network': { **GetNetWork() }, 881 | 'io': { **GetIoReadWrite() }, 882 | 'boot': { **GetBootTime() }, 883 | 'time': time.time() 884 | } 885 | return systemData 886 | 887 | cpuConstants = CpuConstants() 888 | 889 | if __name__ == '__main__': 890 | print(GetFullSystemData()) 891 | print(GetCpuConstants()) 892 | print(GetSystemInfo()) 893 | print(GetNetWork()) 894 | print(GetIoReadWrite()) 895 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # system-info 2 | 基于python3的linux和windows系统信息api 3 | 4 | linux and windows system information api 5 | 6 | ### based on: python3.8 7 | 8 | 所有api均支持linux和windows 9 | 10 | All apis support linux and windows 11 | 12 | # api列表: 13 | 14 | ``` 15 | CpuConstants 16 | ExecShellUnix 17 | GetBootTime 18 | GetCpuConstants 19 | GetCpuInfo 20 | GetDiskInfo 21 | GetDiskInfoUnix 22 | GetDiskInfoWindows 23 | GetErrorInfo 24 | GetFullSystemData 25 | GetIoRead 26 | GetIoReadWrite 27 | GetIoWrite 28 | GetLoadAverage 29 | GetMemInfo 30 | GetMemInfoUnix 31 | GetMemInfoWindows 32 | GetNetWork 33 | GetRegValue 34 | GetSystemInfo 35 | GetSystemVersion 36 | GetSystemVersionUnix 37 | GetSystemVersionWindows 38 | ToSizeInt 39 | ToSizeString 40 | UNIX 41 | cpuConstants 42 | md5 43 | readFile 44 | ``` 45 | 46 | 47 | # api说明: 48 | 49 | ## 当前系统网络使用情况:上传下载速率,收发包 50 | ```python 51 | GetNetWork() 52 | ``` 53 | #### both 54 | ```python 55 | { 56 | 'up': 1.54, 57 | 'down': 0.37, 58 | 'upTotal': 87688289, 59 | 'downTotal': 336439316, 60 | 'downPackets': 397399, 61 | 'upPackets': 262468 62 | } 63 | ``` 64 | 65 | ## 当前系统磁盘IO情况:IO读写 66 | ```python 67 | GetIoReadWrite() 68 | ``` 69 | #### both 70 | ```python 71 | {'write': 1003332, 'read': 1466368} 72 | ``` 73 | 74 | ## 当前系统CPU常量 75 | ```python 76 | GetCpuConstants() 77 | ``` 78 | 79 | #### windows 80 | ```python 81 | {'cpu_count': 1, 'cpu_name': 'AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx ', 'cpu_core': 4, 'cpu_threads': 8} 82 | ``` 83 | 84 | #### linux 85 | ```python 86 | {'cpu_count': 1, 'cpu_name': 'Intel(R) Xeon(R) Platinum 8269CY CPU @ 2.50GHz', 'cpu_core': 1, 'cpu_threads': 1} 87 | ``` 88 | 89 | ## 当前系统CPU信息、使用率 90 | ```python 91 | GetCpuInfo() 92 | ``` 93 | 94 | #### windows 95 | ```python 96 | { 97 | 'used': 17.2, 98 | 'used_list': [23.8, 12.2, 19.6, 10.2, 20.3, 6.2, 12.6, 30.3], 99 | 'cpu_count': 1, 100 | 'cpu_name': 'AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx ', 101 | 'cpu_core': 4, 102 | 'cpu_threads': 8 103 | } 104 | ``` 105 | 106 | #### linux 107 | ```python 108 | { 109 | 'used': 2.0, 110 | 'used_list': [3.4], 111 | 'cpu_count': 1, 112 | 'cpu_name': 'Intel(R) Xeon(R) Platinum 8269CY CPU @ 2.50GHz', 113 | 'cpu_core': 1, 114 | 'cpu_threads': 1 115 | } 116 | ``` 117 | 118 | ## 当前系统负载信息 119 | ```python 120 | GetLoadAverage() 121 | ``` 122 | 123 | #### windows 124 | ```python 125 | { 126 | 'one': 0, 127 | 'five': 0, 128 | 'fifteen': 0, 129 | 'max': 16, 130 | 'limit': 16, 131 | 'safe': 12.0 132 | } 133 | ``` 134 | 135 | #### linux 136 | ```python 137 | { 138 | 'one': 0.46, 139 | 'five': 0.18, 140 | 'fifteen': 0.14, 141 | 'max': 2, 142 | 'limit': 2, 143 | 'safe': 1.5 144 | } 145 | ``` 146 | 147 | ## 当前系统内存使用情况(linux比windows多了cached和buffers) 148 | ```python 149 | GetMemInfo() 150 | ``` 151 | #### windows 152 | ```python 153 | { 154 | 'memTotal': 7069, 155 | 'memFree': 1202, 156 | 'memRealUsed': 5866, 157 | 'menUsedPercent': '82.98' 158 | } 159 | ``` 160 | 161 | #### linux 162 | ```python 163 | { 164 | 'memTotal': 1838, 165 | 'memFree': 181, 166 | 'memBuffers': 25, 167 | 'memCached': 448, 168 | 'memRealUsed': 1184, 169 | 'memUsedPercent': 64.41784548422198 170 | } 171 | ``` 172 | 173 | ## 当前系统磁盘信息 174 | ```python 175 | GetDiskInfo() 176 | ``` 177 | 178 | #### windows 179 | ```python 180 | [{'path': 'C:/', 181 | 'size': {'total': 85899341824, 182 | 'used': 84512485376, 183 | 'free': 1386856448, 184 | 'percent': 98.4}, 185 | 'fstype': 'NTFS', 186 | 'inodes': False}, 187 | {'path': 'D:/', 188 | 'size': {'total': 413524815872, 189 | 'used': 367597920256, 190 | 'free': 45926895616, 191 | 'percent': 88.9}, 192 | 'fstype': 'NTFS', 193 | 'inodes': False}] 194 | ``` 195 | 196 | #### linux 197 | ```python 198 | [{ 199 | 'path': '/', 200 | 'size': ['50G', '16G', '32G', '33%'], 201 | 'inodes': ['3276800', '261498', '3015302', '8%'] 202 | }] 203 | ``` 204 | 205 | 206 | ## 获取系统注册表信息(仅windows可用) 207 | ```python 208 | GetRegValue(key: str, subkey: str, value: str) 209 | ``` 210 | ```python 211 | ''' 212 | 获取系统注册表信息 213 | 214 | Parameters 215 | ---------- 216 | key : str 217 | 类型. 218 | subkey : str 219 | 路径. 220 | value : str 221 | key. 222 | 223 | Returns 224 | ------- 225 | value : Any 226 | DESCRIPTION. 227 | 228 | ''' 229 | ``` 230 | 231 | ## 获取系统版本信息 232 | ```python 233 | GetSystemVersion() 234 | ``` 235 | 236 | #### windows 237 | ```python 238 | Windows 10 Home China (build 18362) x64 (Py3.8.5) 239 | ``` 240 | 241 | #### linux 242 | ```python 243 | CentOS 7.6.1810(Py 3.8.5) 244 | ``` 245 | 246 | ## 获取系统启动时间及运行时间 247 | ```python 248 | GetBootTime() 249 | ``` 250 | 251 | #### both 252 | ```python 253 | {'timestamp': 1597574445.835271, 254 | 'runtime': 33396.16829442978, 255 | 'datetime': '2020-08-17 03:57:22'} 256 | ``` 257 | 258 | ## 获取全部系统信息 259 | ```python 260 | GetFullSystemData() 261 | ``` 262 | 263 | #### windows 264 | ```python 265 | { 266 | 'cpu': { 267 | 'used': 16.0, 268 | 'used_list': [29.0, 16.4, 30.5, 13.9, 28.1, 16.8, 24.0, 26.7], 269 | 'cpu_count': 1, 270 | 'cpu_name': 'AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx ', 271 | 'cpu_core': 4, 272 | 'cpu_threads': 8 273 | }, 274 | 'load': { 275 | 'one': 0, 276 | 'five': 0, 277 | 'fifteen': 0, 278 | 'max': 16, 279 | 'limit': 16, 280 | 'safe': 12.0 281 | }, 282 | 'mem': { 283 | 'memTotal': 7069, 284 | 'memFree': 1181, 285 | 'memRealUsed': 5888, 286 | 'menUsedPercent': '83.29' 287 | }, 288 | 'disk': [{ 289 | 'path': 'C:/', 290 | 'size': { 291 | 'total': 85899341824, 292 | 'used': 84515794944, 293 | 'free': 1383546880, 294 | 'percent': 98.4 295 | }, 296 | 'fstype': 'NTFS', 297 | 'inodes': False 298 | }, { 299 | 'path': 'D:/', 300 | 'size': { 301 | 'total': 413524815872, 302 | 'used': 367597862912, 303 | 'free': 45926952960, 304 | 'percent': 88.9 305 | }, 306 | 'fstype': 'NTFS', 307 | 'inodes': False 308 | }], 309 | 'network': { 310 | 'up': 1.84, 311 | 'down': 2.69, 312 | 'upTotal': 92363508, 313 | 'downTotal': 342344006, 314 | 'downPackets': 409006, 315 | 'upPackets': 271275 316 | }, 317 | 'io': { 318 | 'write': 1277171, 319 | 'read': 38696960 320 | }, 321 | 'boot': { 322 | 'timestamp': 1597574445.966399, 323 | 'runtime': 34064.19006037712, 324 | 'datetime': '2020-08-17 04:08:30' 325 | }, 326 | 'time': 1597608510.1564593 327 | } 328 | ``` 329 | 330 | #### linux 331 | ```python 332 | { 333 | 'cpu': { 334 | 'used': 6.0, 335 | 'used_list': [3.4], 336 | 'cpu_count': 1, 337 | 'cpu_name': 'Intel(R) Xeon(R) Platinum 8269CY CPU @ 2.50GHz', 338 | 'cpu_core': 1, 339 | 'cpu_threads': 1 340 | }, 341 | 'load': { 342 | 'one': 0.59, 343 | 'five': 0.49, 344 | 'fifteen': 0.28, 345 | 'max': 2, 346 | 'limit': 2, 347 | 'safe': 1.5 348 | }, 349 | 'mem': { 350 | 'memTotal': 1838, 351 | 'memFree': 180, 352 | 'memBuffers': 26, 353 | 'memCached': 448, 354 | 'memRealUsed': 1184, 355 | 'memUsedPercent': 64.41784548422198 356 | }, 357 | 'disk': [{ 358 | 'path': '/', 359 | 'size': ['50G', '16G', '32G', '33%'], 360 | 'inodes': ['3276800', '261498', '3015302', '8%'] 361 | }], 362 | 'network': { 363 | 'up': 0.0, 364 | 'down': 0.0, 365 | 'upTotal': 606720149, 366 | 'downTotal': 479946863, 367 | 'downPackets': 1431369, 368 | 'upPackets': 1305962 369 | }, 370 | 'io': { 371 | 'write': 0, 372 | 'read': 0 373 | }, 374 | 'boot': { 375 | 'timestamp': 1597435339.0, 376 | 'runtime': 175312.03097391129, 377 | 'datetime': '2020-08-17 04:44:11' 378 | }, 379 | 'time': 1597610651.0309963 380 | } 381 | ``` 382 | 383 | ## Author 384 | ### Pure-Peace 385 | 386 | ``` 387 | systemInfo.py 388 | ``` 389 | 390 | ```python 391 | # -*- coding: utf-8 -*- 392 | ''' 393 | @name: 系统信息 / SystemInfo 394 | @author: PurePeace 395 | @time: 2020年8月17日 396 | @version: 0.1 397 | ''' 398 | 399 | from typing import List, Dict, Any 400 | 401 | import os 402 | import time 403 | import psutil 404 | import platform 405 | import hashlib 406 | import re 407 | import sys 408 | 409 | 410 | from cachelib import SimpleCache 411 | cache = SimpleCache() 412 | 413 | 414 | UNIX: bool = os.name == 'posix' 415 | SYS: str = platform.system() 416 | 417 | 418 | class CpuConstants: 419 | def __init__(self): 420 | ''' 421 | 初始化CPU常量(多平台) 422 | Returns 423 | ------- 424 | self. 425 | ''' 426 | self.WMI = None 427 | self.initialed: bool = False 428 | self.cpuList: list = [] # windows only 429 | 430 | self.cpuCount: int = 0 # 物理cpu数量 431 | self.cpuCore: int = 0 # cpu物理核心数 432 | self.cpuThreads: int = 0 # cpu逻辑核心数 433 | self.cpuName: str = '' # cpu型号 434 | 435 | self.Update(True) 436 | 437 | 438 | def Update(self, update: bool = False) -> None: 439 | ''' 440 | 更新cpu数据 441 | Returns 442 | ------- 443 | None. 444 | ''' 445 | if UNIX: self.GetCpuConstantsUnix(update) 446 | else: self.GetCpuConstantsWindows(update) 447 | 448 | self.initialed: bool = True 449 | 450 | 451 | @property 452 | def getDict(self) -> Dict[int, str]: 453 | ''' 454 | 以字典格式获取当前cpu常量 455 | Returns 456 | ------- 457 | Dict[int, str] 458 | DESCRIPTION. 459 | ''' 460 | if not self.initialed: self.Update() 461 | return { 462 | 'cpu_count': self.cpuCount, 463 | 'cpu_name': self.cpuName, 464 | 'cpu_core': self.cpuCore, 465 | 'cpu_threads': self.cpuThreads 466 | } 467 | 468 | 469 | def GetCpuConstantsUnix(self, update: bool = False) -> None: 470 | ''' 471 | 获取unix下的cpu信息 472 | Parameters 473 | ---------- 474 | update : bool, optional 475 | DESCRIPTION. The default is False. 476 | Returns 477 | ------- 478 | None 479 | DESCRIPTION. 480 | ''' 481 | if update or not self.initialed: 482 | ids: list = re.findall("physical id.+", readFile('/proc/cpuinfo')) 483 | 484 | # 物理cpu个数 485 | self.cpuCount: int = len(set(ids)) 486 | 487 | # cpu型号(名称) 488 | self.cpuName: str = self.getCpuTypeUnix() 489 | 490 | 491 | self.GetCpuConstantsBoth() 492 | 493 | 494 | def InitWmi(self) -> None: 495 | ''' 496 | 初始化wmi(for windows) 497 | Returns 498 | ------- 499 | None 500 | DESCRIPTION. 501 | ''' 502 | import wmi 503 | self.WMI = wmi.WMI() 504 | 505 | 506 | def GetCpuConstantsBoth(self, update: bool = False) -> None: 507 | ''' 508 | 获取多平台共用的cpu信息 509 | Parameters 510 | ---------- 511 | update : bool, optional 512 | 强制更新数据. The default is False. 513 | Returns 514 | ------- 515 | None 516 | DESCRIPTION. 517 | ''' 518 | if update or not self.initialed: 519 | 520 | # cpu逻辑核心数 521 | self.cpuThreads: int = psutil.cpu_count() 522 | 523 | # cpu物理核心数 524 | self.cpuCore: int = psutil.cpu_count(logical=False) 525 | 526 | 527 | def GetCpuConstantsWindows(self, update: bool = False) -> None: 528 | ''' 529 | 获取windows平台的cpu信息 530 | Parameters 531 | ---------- 532 | update : bool, optional 533 | 强制更新数据. The default is False. 534 | Returns 535 | ------- 536 | None 537 | DESCRIPTION. 538 | ''' 539 | if update or not self.initialed: 540 | 541 | # 初始化wmi 542 | if self.WMI == None: self.InitWmi() 543 | 544 | # cpu列表 545 | self.cpuList: list = self.WMI.Win32_Processor() 546 | 547 | # 物理cpu个数 548 | self.cpuCount: int = len(self.cpuList) 549 | 550 | # cpu型号(名称) 551 | self.cpuName: str = self.cpuList[0].Name 552 | 553 | 554 | self.GetCpuConstantsBoth() 555 | 556 | 557 | @staticmethod 558 | def getCpuTypeUnix() -> str: 559 | ''' 560 | 获取CPU型号(unix) 561 | Returns 562 | ------- 563 | str 564 | CPU型号. 565 | ''' 566 | cpuinfo: str = readFile('/proc/cpuinfo') 567 | rep: str = 'model\s+name\s+:\s+(.+)' 568 | tmp = re.search(rep,cpuinfo,re.I) 569 | cpuType: str = '' 570 | if tmp: 571 | cpuType: str = tmp.groups()[0] 572 | else: 573 | cpuinfo = ExecShellUnix('LANG="en_US.UTF-8" && lscpu')[0] 574 | rep = 'Model\s+name:\s+(.+)' 575 | tmp = re.search(rep,cpuinfo,re.I) 576 | if tmp: cpuType = tmp.groups()[0] 577 | return cpuType 578 | 579 | 580 | def GetCpuInfo(interval: int = 1) -> Dict[str, Any]: 581 | ''' 582 | 获取CPU信息 583 | Parameters 584 | ---------- 585 | interval : int, optional 586 | DESCRIPTION. The default is 1. 587 | Returns 588 | ------- 589 | Dict[float, list, dict] 590 | DESCRIPTION. 591 | ''' 592 | time.sleep(0.5) 593 | 594 | 595 | # cpu总使用率 596 | used: float = psutil.cpu_percent(interval) 597 | 598 | # 每个逻辑cpu使用率 599 | usedList: List[float] = psutil.cpu_percent(percpu=True) 600 | 601 | 602 | return {'used': used, 'used_list': usedList, **cpuConstants.getDict} 603 | 604 | 605 | def readFile(filename: str) -> str: 606 | ''' 607 | 读取文件内容 608 | Parameters 609 | ---------- 610 | filename : str 611 | 文件名. 612 | Returns 613 | ------- 614 | str 615 | 文件内容. 616 | ''' 617 | try: 618 | with open(filename, 'r', encoding='utf-8') as file: return file.read() 619 | except: 620 | pass 621 | 622 | return '' 623 | 624 | 625 | def GetLoadAverage() -> dict: 626 | ''' 627 | 获取服务器负载状态(多平台) 628 | Returns 629 | ------- 630 | dict 631 | DESCRIPTION. 632 | ''' 633 | try: c: list = os.getloadavg() 634 | except: c: list = [0,0,0] 635 | data: dict = {i: c[idx] for idx, i in enumerate(('one', 'five', 'fifteen'))} 636 | data['max'] = psutil.cpu_count() * 2 637 | data['limit'] = data['max'] 638 | data['safe'] = data['max'] * 0.75 639 | return data 640 | 641 | 642 | def GetMemInfo() -> dict: 643 | ''' 644 | 获取内存信息(多平台) 645 | Returns 646 | ------- 647 | dict 648 | DESCRIPTION. 649 | ''' 650 | if UNIX: return GetMemInfoUnix() 651 | return GetMemInfoWindows() 652 | 653 | 654 | def GetMemInfoUnix() -> Dict[str, int]: 655 | ''' 656 | 获取内存信息(unix) 657 | Returns 658 | ------- 659 | dict 660 | DESCRIPTION. 661 | ''' 662 | mem = psutil.virtual_memory() 663 | memInfo: dict = { 664 | 'memTotal': ToSizeInt(mem.total, 'MB'), 665 | 'memFree': ToSizeInt(mem.free, 'MB'), 666 | 'memBuffers': ToSizeInt(mem.buffers, 'MB'), 667 | 'memCached': ToSizeInt(mem.cached, 'MB'), 668 | } 669 | memInfo['memRealUsed'] = \ 670 | memInfo['memTotal'] - \ 671 | memInfo['memFree'] - \ 672 | memInfo['memBuffers'] - \ 673 | memInfo['memCached'] 674 | 675 | memInfo['memUsedPercent'] = memInfo['memRealUsed'] / memInfo['memTotal'] * 100 676 | 677 | return memInfo 678 | 679 | 680 | def GetMemInfoWindows() -> dict: 681 | ''' 682 | 获取内存信息(windows) 683 | Returns 684 | ------- 685 | dict 686 | DESCRIPTION. 687 | ''' 688 | mem = psutil.virtual_memory() 689 | memInfo: dict = { 690 | 'memTotal': ToSizeInt(mem.total, 'MB'), 691 | 'memFree': ToSizeInt(mem.free, 'MB'), 692 | 'memRealUsed': ToSizeInt(mem.used, 'MB'), 693 | 'menUsedPercent': mem.used / mem.total * 100 694 | } 695 | 696 | return memInfo 697 | 698 | 699 | def ToSizeInt(byte: int, target: str) -> int: 700 | ''' 701 | 将字节大小转换为目标单位的大小 702 | Parameters 703 | ---------- 704 | byte : int 705 | int格式的字节大小(bytes size) 706 | target : str 707 | 目标单位,str. 708 | Returns 709 | ------- 710 | int 711 | 转换为目标单位后的字节大小. 712 | ''' 713 | return int(byte/1024**(('KB','MB','GB','TB').index(target) + 1)) 714 | 715 | 716 | def ToSizeString(byte: int) -> str: 717 | ''' 718 | 获取字节大小字符串 719 | Parameters 720 | ---------- 721 | byte : int 722 | int格式的字节大小(bytes size). 723 | Returns 724 | ------- 725 | str 726 | 自动转换后的大小字符串,如:6.90 GB. 727 | ''' 728 | units: tuple = ('b','KB','MB','GB','TB') 729 | re = lambda: '{:.2f} {}'.format(byte, u) 730 | for u in units: 731 | if byte < 1024: return re() 732 | byte /= 1024 733 | return re() 734 | 735 | 736 | def GetDiskInfo() -> list: 737 | ''' 738 | 获取磁盘信息(多平台) 739 | Returns 740 | ------- 741 | list 742 | 列表. 743 | ''' 744 | try: 745 | if UNIX: return GetDiskInfoUnix() 746 | return GetDiskInfoWindows() 747 | except Exception as err: 748 | print('获取磁盘信息异常(unix: {}):'.format(UNIX), err) 749 | return [] 750 | 751 | 752 | def GetDiskInfoWindows() -> list: 753 | ''' 754 | 获取磁盘信息Windows 755 | Returns 756 | ------- 757 | diskInfo : list 758 | 列表. 759 | ''' 760 | diskIo: list = psutil.disk_partitions() 761 | diskInfo: list = [] 762 | for disk in diskIo: 763 | tmp: dict = {} 764 | try: 765 | tmp['path'] = disk.mountpoint.replace("\\","/") 766 | usage = psutil.disk_usage(disk.mountpoint) 767 | tmp['size'] = { 768 | 'total': usage.total, 769 | 'used': usage.used, 770 | 'free': usage.free, 771 | 'percent': usage.percent 772 | } 773 | tmp['fstype'] = disk.fstype 774 | tmp['inodes'] = False 775 | diskInfo.append(tmp) 776 | except: 777 | pass 778 | return diskInfo 779 | 780 | 781 | def GetDiskInfoUnix() -> list: 782 | ''' 783 | 获取硬盘分区信息(unix) 784 | Returns 785 | ------- 786 | list 787 | DESCRIPTION. 788 | ''' 789 | temp: list = ( 790 | ExecShellUnix("df -h -P|grep '/'|grep -v tmpfs")[0]).split('\n') 791 | tempInodes: list = ( 792 | ExecShellUnix("df -i -P|grep '/'|grep -v tmpfs")[0]).split('\n') 793 | diskInfo: list = [] 794 | n: int = 0 795 | cuts: list = [ 796 | '/mnt/cdrom', 797 | '/boot', 798 | '/boot/efi', 799 | '/dev', 800 | '/dev/shm', 801 | '/run/lock', 802 | '/run', 803 | '/run/shm', 804 | '/run/user' 805 | ] 806 | for tmp in temp: 807 | n += 1 808 | try: 809 | inodes: list = tempInodes[n-1].split() 810 | disk: list = tmp.split() 811 | if len(disk) < 5: continue 812 | if disk[1].find('M') != -1: continue 813 | if disk[1].find('K') != -1: continue 814 | if len(disk[5].split('/')) > 10: continue 815 | if disk[5] in cuts: continue 816 | if disk[5].find('docker') != -1: continue 817 | arr = {} 818 | arr['path'] = disk[5] 819 | tmp1 = [disk[1],disk[2],disk[3],disk[4]] 820 | arr['size'] = tmp1 821 | arr['inodes'] = [inodes[1],inodes[2],inodes[3],inodes[4]] 822 | diskInfo.append(arr) 823 | except Exception as ex: 824 | print('信息获取错误:', str(ex)) 825 | continue 826 | return diskInfo 827 | 828 | 829 | 830 | def md5(strings: str) -> str: 831 | ''' 832 | 生成md5 833 | Parameters 834 | ---------- 835 | strings : TYPE 836 | 要进行hash处理的字符串 837 | Returns 838 | ------- 839 | str[32] 840 | hash后的字符串. 841 | ''' 842 | 843 | m = hashlib.md5() 844 | m.update(strings.encode('utf-8')) 845 | return m.hexdigest() 846 | 847 | 848 | def GetErrorInfo() -> str: 849 | ''' 850 | 获取traceback中的错误 851 | Returns 852 | ------- 853 | str 854 | DESCRIPTION. 855 | ''' 856 | import traceback 857 | errorMsg = traceback.format_exc() 858 | return errorMsg 859 | 860 | 861 | def ExecShellUnix(cmdstring: str, shell=True): 862 | ''' 863 | 执行Shell命令(Unix) 864 | Parameters 865 | ---------- 866 | cmdstring : str 867 | DESCRIPTION. 868 | shell : TYPE, optional 869 | DESCRIPTION. The default is True. 870 | Returns 871 | ------- 872 | a : TYPE 873 | DESCRIPTION. 874 | e : TYPE 875 | DESCRIPTION. 876 | ''' 877 | a: str = '' 878 | e: str = '' 879 | import subprocess,tempfile 880 | 881 | try: 882 | rx: str = md5(cmdstring) 883 | succ_f = tempfile.SpooledTemporaryFile( 884 | max_size = 4096, 885 | mode = 'wb+', 886 | suffix = '_succ', 887 | prefix = 'btex_' + rx , 888 | dir = '/dev/shm' 889 | ) 890 | err_f = tempfile.SpooledTemporaryFile( 891 | max_size = 4096, 892 | mode = 'wb+', 893 | suffix = '_err', 894 | prefix = 'btex_' + rx , 895 | dir = '/dev/shm' 896 | ) 897 | sub = subprocess.Popen( 898 | cmdstring, 899 | close_fds = True, 900 | shell = shell, 901 | bufsize = 128, 902 | stdout = succ_f, 903 | stderr = err_f 904 | ) 905 | sub.wait() 906 | err_f.seek(0) 907 | succ_f.seek(0) 908 | a = succ_f.read() 909 | e = err_f.read() 910 | if not err_f.closed: err_f.close() 911 | if not succ_f.closed: succ_f.close() 912 | except Exception as err: 913 | print(err) 914 | try: 915 | if type(a) == bytes: a = a.decode('utf-8') 916 | if type(e) == bytes: e = e.decode('utf-8') 917 | except Exception as err: 918 | print(err) 919 | 920 | return a,e 921 | 922 | 923 | def GetNetWork() -> dict: 924 | ''' 925 | 获取系统网络信息 926 | Returns 927 | ------- 928 | dict 929 | DESCRIPTION. 930 | ''' 931 | networkIo: list = [0,0,0,0] 932 | cache_timeout: int = 86400 933 | try: 934 | networkIo = psutil.net_io_counters()[:4] 935 | except: 936 | pass 937 | 938 | otime = cache.get("otime") 939 | if not otime: 940 | otime = time.time() 941 | cache.set('up',networkIo[0],cache_timeout) 942 | cache.set('down',networkIo[1],cache_timeout) 943 | cache.set('otime',otime ,cache_timeout) 944 | 945 | ntime = time.time() 946 | networkInfo: dict = {'up': 0, 'down': 0} 947 | networkInfo['upTotal'] = networkIo[0] 948 | networkInfo['downTotal'] = networkIo[1] 949 | try: 950 | networkInfo['up'] = round( 951 | float(networkIo[0] - cache.get("up")) / 1024 / (ntime - otime), 952 | 2 953 | ) 954 | networkInfo['down'] = round( 955 | float(networkIo[1] - cache.get("down")) / 1024 / (ntime - otime), 956 | 2 957 | ) 958 | except: 959 | pass 960 | 961 | networkInfo['downPackets'] = networkIo[3] 962 | networkInfo['upPackets'] = networkIo[2] 963 | 964 | cache.set('up',networkIo[0],cache_timeout) 965 | cache.set('down',networkIo[1],cache_timeout) 966 | cache.set('otime', time.time(),cache_timeout) 967 | 968 | return networkInfo 969 | 970 | 971 | def GetSystemInfo() -> dict: 972 | systemInfo: dict = {} 973 | systemInfo['cpu'] = GetCpuInfo() 974 | systemInfo['load'] = GetLoadAverage() 975 | systemInfo['mem'] = GetMemInfo() 976 | systemInfo['disk'] = GetDiskInfo() 977 | 978 | return systemInfo 979 | 980 | 981 | 982 | def GetIoReadWrite() -> Dict[str, int]: 983 | ''' 984 | 获取系统IO读写 985 | Returns 986 | ------- 987 | dict 988 | DESCRIPTION. 989 | ''' 990 | ioDisk = psutil.disk_io_counters() 991 | ioTotal: dict = {} 992 | ioTotal['write'] = GetIoWrite(ioDisk.write_bytes) 993 | ioTotal['read'] = GetIoRead(ioDisk.read_bytes) 994 | return ioTotal 995 | 996 | 997 | def GetIoWrite(ioWrite: int) -> int: 998 | ''' 999 | 获取IO写 1000 | Parameters 1001 | ---------- 1002 | ioWrite : TYPE 1003 | DESCRIPTION. 1004 | Returns 1005 | ------- 1006 | int 1007 | DESCRIPTION. 1008 | ''' 1009 | diskWrite: int = 0 1010 | oldWrite: int = cache.get('io_write') 1011 | if not oldWrite: 1012 | cache.set('io_write', ioWrite) 1013 | return diskWrite; 1014 | 1015 | oldTime: float = cache.get('io_time') 1016 | newTime: float = time.time() 1017 | if not oldTime: oldTime = newTime 1018 | ioEnd: int = (ioWrite - oldWrite) 1019 | timeEnd: float = (time.time() - oldTime) 1020 | if ioEnd > 0: 1021 | if timeEnd < 1: timeEnd = 1 1022 | diskWrite = ioEnd / timeEnd 1023 | cache.set('io_write',ioWrite) 1024 | cache.set('io_time',newTime) 1025 | if diskWrite > 0: return int(diskWrite) 1026 | return 0 1027 | 1028 | 1029 | def GetIoRead(ioRead): 1030 | ''' 1031 | 读取IO读 1032 | Parameters 1033 | ---------- 1034 | ioRead : TYPE 1035 | DESCRIPTION. 1036 | Returns 1037 | ------- 1038 | TYPE 1039 | DESCRIPTION. 1040 | ''' 1041 | diskRead: int = 0 1042 | oldRead: int = cache.get('io_read') 1043 | if not oldRead: 1044 | cache.set('io_read',ioRead) 1045 | return diskRead; 1046 | oldTime: float = cache.get('io_time') 1047 | newTime: float = time.time() 1048 | if not oldTime: oldTime = newTime 1049 | ioEnd: int = (ioRead - oldRead) 1050 | timeEnd: float = (time.time() - oldTime) 1051 | if ioEnd > 0: 1052 | if timeEnd < 1: timeEnd = 1; 1053 | diskRead = ioEnd / timeEnd; 1054 | cache.set('io_read', ioRead) 1055 | if diskRead > 0: return int(diskRead) 1056 | return 0 1057 | 1058 | 1059 | def GetRegValue(key: str, subkey: str, value: str) -> Any: 1060 | ''' 1061 | 获取系统注册表信息 1062 | Parameters 1063 | ---------- 1064 | key : str 1065 | 类型. 1066 | subkey : str 1067 | 路径. 1068 | value : str 1069 | key. 1070 | Returns 1071 | ------- 1072 | value : Any 1073 | DESCRIPTION. 1074 | ''' 1075 | import winreg 1076 | key = getattr(winreg, key) 1077 | handle = winreg.OpenKey(key, subkey) 1078 | (value, type) = winreg.QueryValueEx(handle, value) 1079 | return value 1080 | 1081 | 1082 | def GetSystemVersion() -> str: 1083 | ''' 1084 | 获取操作系统版本(多平台) 1085 | Returns 1086 | ------- 1087 | str 1088 | DESCRIPTION. 1089 | ''' 1090 | if UNIX: return GetSystemVersionUnix() 1091 | return GetSystemVersionWindows() 1092 | 1093 | 1094 | def GetSystemVersionWindows() -> str: 1095 | ''' 1096 | 获取操作系统版本(windows) 1097 | Returns 1098 | ------- 1099 | str 1100 | DESCRIPTION. 1101 | ''' 1102 | try: 1103 | import platform 1104 | bit: str = 'x86'; 1105 | if 'PROGRAMFILES(X86)' in os.environ: bit = 'x64' 1106 | 1107 | def get(key: str): 1108 | return GetRegValue( 1109 | "HKEY_LOCAL_MACHINE", 1110 | "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 1111 | key 1112 | ) 1113 | 1114 | osName = get('ProductName') 1115 | build = get('CurrentBuildNumber') 1116 | 1117 | version: str = '{} (build {}) {} (Py{})'.format( 1118 | osName, build, bit, platform.python_version()) 1119 | return version 1120 | except Exception as ex: 1121 | print('获取系统版本失败,错误:' + str(ex)) 1122 | return '未知系统版本.' 1123 | 1124 | 1125 | def GetSystemVersionUnix() -> str: 1126 | ''' 1127 | 获取系统版本(unix) 1128 | Returns 1129 | ------- 1130 | str 1131 | 系统版本. 1132 | ''' 1133 | try: 1134 | version: str = readFile('/etc/redhat-release') 1135 | if not version: 1136 | version = readFile( 1137 | '/etc/issue' 1138 | ).strip().split("\n")[0].replace('\\n','').replace('\l','').strip() 1139 | else: 1140 | version = version.replace( 1141 | 'release ','' 1142 | ).replace('Linux','').replace('(Core)','').strip() 1143 | v = sys.version_info 1144 | return version + '(Py {}.{}.{})'.format(v.major, v.minor, v.micro) 1145 | except Exception as err: 1146 | print('获取系统版本失败,错误:', err) 1147 | return '未知系统版本.' 1148 | 1149 | 1150 | def GetBootTime() -> dict: 1151 | ''' 1152 | 获取当前系统启动时间 1153 | Returns 1154 | ------- 1155 | dict 1156 | DESCRIPTION. 1157 | ''' 1158 | bootTime: float = psutil.boot_time() 1159 | return { 1160 | 'timestamp': bootTime, 1161 | 'runtime': time.time() - bootTime, 1162 | 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) 1163 | } 1164 | 1165 | 1166 | def GetCpuConstants() -> dict: 1167 | ''' 1168 | 获取CPU常量信息 1169 | Parameters 1170 | ---------- 1171 | cpuConstants : CpuConstants 1172 | DESCRIPTION. 1173 | Returns 1174 | ------- 1175 | dict 1176 | DESCRIPTION. 1177 | ''' 1178 | return cpuConstants.getDict 1179 | 1180 | 1181 | def GetFullSystemData() -> dict: 1182 | ''' 1183 | 获取完全的系统信息 1184 | Returns 1185 | ------- 1186 | dict 1187 | DESCRIPTION. 1188 | ''' 1189 | systemData: dict = { 1190 | **GetSystemInfo(), 1191 | 'network': { **GetNetWork() }, 1192 | 'io': { **GetIoReadWrite() }, 1193 | 'boot': { **GetBootTime() }, 1194 | 'time': time.time() 1195 | } 1196 | return systemData 1197 | 1198 | cpuConstants = CpuConstants() 1199 | 1200 | if __name__ == '__main__': 1201 | print(GetFullSystemData()) 1202 | print(GetCpuConstants()) 1203 | print(GetSystemInfo()) 1204 | print(GetNetWork()) 1205 | print(GetIoReadWrite()) 1206 | ``` 1207 | --------------------------------------------------------------------------------