转载请注明出处:http://blog.csdn.net/dysj4099
前面的文章《利用Linux守护进程机制完成一个简单系统监控demo》中提到在Linux中如何利用Python读取procfs中的信息,并构建基于守护进程的系统运行状况监控程序。但目前云平台中Windows虚拟机的数量还是占大多数,虽然可以利用libvirt提供的API获取虚拟机的运行信息,不过对于Windows虚拟机来说,获取到的大部分系统信息都不准确,甚至是错误的。因此,一种解决方法是在Windows虚拟机中定制一个监控agent,通过agent实时获取系统信息并发布。
在Linux下,操作系统提供了procfs这样一种文件系统方便获取系统的各项运行信息。但Windows并没有提供类似procfs的机制,就必须另想办法了。好在微软提供了WMI(Windows Management Instrumentation)这样一种管理技术,它允许通过一个公共接口访问多种操作系统的构成单元,实现对操作系统的信息获取及管理操作。本文正是利用WMI进行数据获取。
要利用Python调用WMI获取信息,必须安装相关的软件包:
根据你的操作系统版本,下载相应版本安装。安装完后,就可以开始了:
CPU信息获取
我们首先以CPU为例,演示Python调用WMI的过程。在此我们调用了Win32_Processor这个类来获取cpu的信息,可以看到这个类的对象包含了与处理器相关的大部分有用信息,对于多核的处理器而言,将输出多个对象。其中LoadPercentage这个参数是指上一秒此处理器的工作负载,这就是我们需要的cpu_usage。
详细的Win32_Processor class说明,请参阅开发文档:
import wmi import os import sys import platform import time import win32com.client as client class DataPollster(object): def get_cpu(self): # Initilization c = wmi.WMI() data_dict = {} for cpu in c.Win32_Processor(): device = cpu.DeviceID.lower() # Get cpu_usage data_dict[device] = {‘volume‘:float(cpu.LoadPercentage), ‘unit‘:‘%‘} return data_dict
Memory信息获取
通过Win32_ComputerSystem可以获取机器内存总大小TotalPhysicalMemory,通过Win32_OperatingSystem获取可用内存大小,而Win32_PageFileUsage可以帮助我们获取虚拟内存及交换内存的相关信息。
def get_mem(self): c = wmi.WMI () cs = c.Win32_ComputerSystem() os = c.Win32_OperatingSystem() pfu = c.Win32_PageFileUsage() data_dict = {} data_dict["MemTotal"] = {‘volume‘:float(cs[0].TotalPhysicalMemory) / (1024*1024), ‘unit‘:‘MB‘} data_dict["MemFree"] = {‘volume‘:float(os[0].FreePhysicalMemory)/1024, ‘unit‘:‘MB‘} data_dict["SwapTotal"] = {‘volume‘:float(pfu[0].AllocatedBaseSize), ‘unit‘:‘MB‘} data_dict["SwapFree"] = {‘volume‘:float(pfu[0].AllocatedBaseSize - pfu[0].CurrentUsage), ‘unit‘:‘MB‘} return {‘data‘:data_dict, ‘timestamp‘:time.asctime(time.localtime())}
Disk信息获取
跟CPU和mem类似,我们可以通过Win32_LogicalDisk获取磁盘信息,包括驱动器号、总容量、空闲容量、文件系统类型等。不同的是通过以下代码我们将看到磁盘实时I/O的获取方式。在这里我们通过Win32_PerfFormattedData_PerfDisk_LogicalDisk对象获取到逻辑磁盘的性能数,这个对象不能直接获取,必须通过WbemScripting.SWbemRefresher加入,并通过Refresh方法来刷新获取数据。这也适用于网络实时流量等数据的获取。
def get_disk(self): c = wmi.WMI () data_dict = {} data_dict[‘total_available‘] = 0 data_dict[‘total_capacity‘] = 0 data_dict[‘total_free‘] = 0 # DriveType=3 : "Local Disk", for disk in c.Win32_LogicalDisk (DriveType=3): data_dict[‘total_available‘] += round(float(disk.FreeSpace) / (1024*1024*1024), 2) data_dict[‘total_capacity‘] += round(float(disk.Size) / (1024*1024*1024), 2) data_dict[‘total_free‘] += round(float(disk.FreeSpace) / (1024*1024*1024), 2) dev_tmp = {} dev_tmp[‘dev‘] = disk.DeviceID dev_tmp[‘available‘] = {‘volume‘:round(float(disk.FreeSpace) / (1024*1024*1024), 2), ‘unit‘:‘GB‘} dev_tmp[‘capacity‘] = {‘volume‘:round(float(disk.Size) / (1024*1024*1024), 2), ‘unit‘:‘GB‘} dev_tmp[‘free‘] = {‘volume‘:round(float(disk.FreeSpace) / (1024*1024*1024), 2), ‘unit‘:‘GB‘} dev_tmp[‘fstype‘] = disk.FileSystem dev_tmp[‘mnt‘] = ‘‘ dev_tmp[‘used‘] = round(long(disk.FreeSpace) / long(disk.Size), 2) data_dict[disk.DeviceID] = dev_tmp com = client.Dispatch("WbemScripting.SWbemRefresher") obj = client.GetObject("winmgmts:\\root\cimv2") diskitems = com.AddEnum(obj, "Win32_PerfFormattedData_PerfDisk_LogicalDisk").objectSet com.Refresh() for item in diskitems: if item.Name in data_dict: data_dict[item.Name][‘io_stat‘] = {} data_dict[item.Name][‘io_stat‘][‘r/s‘] = {‘volume‘:float(item.DiskReadsPerSec), ‘unit‘:‘‘} data_dict[item.Name][‘io_stat‘][‘w/s‘] = {‘volume‘:float(item.DiskWritesPerSec), ‘unit‘:‘‘} data_dict[item.Name][‘io_stat‘][‘rkB/s‘] = {‘volume‘:(float(item.DiskReadBytesPerSec) / 1024), ‘unit‘:‘KB/s‘} data_dict[item.Name][‘io_stat‘][‘wkB/s‘] = {‘volume‘:(float(item.DiskWriteBytesPerSec) / 1024), ‘unit‘:‘KB/s‘} return {‘data‘:data_dict, ‘timestamp‘:time.asctime(time.localtime())}
Net信息获取
照葫芦画瓢,Net可以通过以下方式获取:
def get_net(self): c = wmi.WMI () com = client.Dispatch("WbemScripting.SWbemRefresher") obj = client.GetObject("winmgmts:\\root\cimv2") items = com.AddEnum(obj, "Win32_PerfRawData_Tcpip_NetworkInterface").objectSet data_dict = {} interfaces = [] for interface in c.Win32_NetworkAdapterConfiguration (IPEnabled=1): print interface.IPAddress[0] interfaces.append(interface.Description) net_bytes_in = 0 net_bytes_out = 0 net_pkts_in = 0 net_pkts_out = 0 com.Refresh() for item in items: if item.Name in interfaces: #print ‘Name:%s -> B_in:%s, B_out:%s, P_in:%s, P_out:%s‘ %(item.Name, item.BytesReceivedPerSec, item.BytesSentPerSec, item.PacketsReceivedPerSec, item.PacketsSentPerSec) net_bytes_in += long(item.BytesReceivedPerSec) net_bytes_out += long(item.BytesSentPerSec) net_pkts_in += long(item.PacketsReceivedPerSec) net_pkts_out += long(item.PacketsSentPerSec) time.sleep(1) net_bytes_in_cur = 0 net_bytes_out_cur = 0 com.Refresh() for item in items: if item.Name in interfaces: net_bytes_in = long(item.BytesReceivedPerSec) - net_bytes_in net_bytes_in_cur += long(item.BytesReceivedPerSec) net_bytes_out = long(item.BytesSentPerSec) - net_bytes_out net_bytes_out_cur += long(item.BytesSentPerSec) net_pkts_in = long(item.PacketsReceivedPerSec) - net_pkts_in net_pkts_out = long(item.PacketsSentPerSec) - net_pkts_out data_dict[‘net_bytes_in‘] = {‘volume‘:net_bytes_in, ‘unit‘:‘B/s‘} data_dict[‘net_bytes_in_sum‘] = {‘volume‘:net_bytes_in_cur, ‘unit‘:‘B‘} data_dict[‘net_bytes_out‘] = {‘volume‘:net_bytes_out, ‘unit‘:‘B/s‘} data_dict[‘net_bytes_out_sum‘] = {‘volume‘:net_bytes_out_cur, ‘unit‘:‘B‘} data_dict[‘net_pkts_in‘] = {‘volume‘:net_pkts_in, ‘unit‘:‘p/s‘} data_dict[‘net_pkts_out‘] = {‘volume‘:net_pkts_out, ‘unit‘:‘p/s‘} return {‘data‘:data_dict, ‘timestamp‘:time.asctime(time.localtime())}
需要注意的是,虽然在Win32_PerfRawData_Tcpip_NetworkInterface的文档中,BytesReceivedPerSec被解释为“Rate at which bytes are received on the interface, including framing characters.”,但是我仍然发现这类以PerSec结尾的参数都是累积值而不是真正的速率,因此我使用休眠1秒后取delta的方式求网卡的瞬时速率。
小结:
本文通过几个例子说明如何使用Python通过WMI获取Windows系统信息。其中涉及到的Win32类定义请参阅微软官方开发文档。下篇将演示如何用Windows服务框架包装监控轮询任务。