def collect_counters(self): counters, instances = win32pdh.EnumObjectItems( None, self._machine_name, self.class_name, win32pdh.PERF_DETAIL_WIZARD ) if self._instance_name is None and len(instances) > 0: all_instances = set() for inst in instances: path = self._make_counter_path(self._machine_name, self._counter_name, inst, counters) if not path: continue all_instances.add(inst) try: if inst not in self.counterdict: self.logger.debug('Adding instance `%s`', inst) self.counterdict[inst] = win32pdh.AddCounter(self.hq, path) except: # noqa: E722, B001 self.logger.fatal( "Failed to create counter. No instances of %s\\%s" % (self.class_name, self._counter_name) ) expired_instances = set(self.counterdict) - all_instances for inst in expired_instances: self.logger.debug('Removing expired instance `%s`', inst) del self.counterdict[inst] else: if self._instance_name is not None: # check to see that it's valid if len(instances) <= 0: self.logger.error( "%s doesn't seem to be a multi-instance counter, but asked for specific instance %s", self.class_name, self._instance_name, ) raise AttributeError("%s is not a multi-instance counter" % self.class_name) if self._instance_name not in instances: self.logger.error("%s is not a counter instance in %s", self._instance_name, self.class_name) raise AttributeError("%s is not an instance of %s" % (self._instance_name, self.class_name)) path = self._make_counter_path(self._machine_name, self._counter_name, self._instance_name, counters) if not path: self.logger.warning("Empty path returned") elif win32pdh.ValidatePath(path) != 0: # Multi-instance counter with no instances presently pass else: try: if SINGLE_INSTANCE_KEY not in self.counterdict: self.logger.debug('Adding single instance for path `%s`', path) self.counterdict[SINGLE_INSTANCE_KEY] = win32pdh.AddCounter(self.hq, path) except: # noqa: E722, B001 self.logger.fatal( "Failed to create counter. No instances of %s\\%s" % (self.class_name, self._counter_name) ) raise self._is_single_instance = True
def build_counter(obj, instance, instance_index, counter): r""" Makes a fully resolved counter path. Counter names are formatted like this: ``\Processor(*)\% Processor Time`` The above breaks down like this: obj = 'Processor' instance = '*' counter = '% Processor Time' Args: obj (str): The top level object instance (str): The instance of the object instance_index (int): The index of the instance. Can usually be 0 counter (str): The name of the counter Returns: Counter: A Counter object with the path if valid Raises: CommandExecutionError: If the path is invalid """ path = win32pdh.MakeCounterPath( (None, obj, instance, None, instance_index, counter), 0 ) if win32pdh.ValidatePath(path) == 0: return Counter(path, obj, instance, instance_index, counter) raise CommandExecutionError("Invalid counter specified: {0}".format(path))
def browse(counterset): """ Explore performance counters. You'll need to install pywin32 manually beforehand. """ # Leave imports in function to not add the dependencies import win32pdh if not counterset: echo_info('Searching for available countersets:') countersets = sorted( win32pdh.EnumObjects(None, None, win32pdh.PERF_DETAIL_WIZARD, True)) for name in countersets: echo_info(name) return description_prefix = ' Description: ' description_indent = ' ' * len(description_prefix) def display_counter(handle): counter_info = win32pdh.GetCounterInfo(handle, True) counter_description = counter_info[-1] counter_type = counter_info[0] if counter_type in COUNTER_TYPES: counter_type_name = COUNTER_TYPES[counter_type][0] else: counter_type_name = 'unknown' echo_info(f'--> {counter}') echo_info(f' Type: {counter_type_name}') echo_info(description_prefix, nl=False) echo_info( textwrap.indent(textwrap.fill(counter_description), description_indent).lstrip()) query_handle = win32pdh.OpenQuery() try: header = f'<<< {counterset} >>>' echo_info(header) echo_info('-' * len(header)) echo_info('') counters, instances = win32pdh.EnumObjectItems( None, None, counterset, win32pdh.PERF_DETAIL_WIZARD) counters.sort() if instances: header = 'Instances' echo_info(header) echo_info('=' * len(header)) instance_index = defaultdict(int) for instance in instances: instance_index[instance] += 1 echo_info(instance) echo_info('') header = 'Counters' echo_info(header) echo_info('=' * len(header)) for counter in counters: for instance, num_instances in instance_index.items(): for index in range(num_instances): path = win32pdh.MakeCounterPath( (None, counterset, instance, None, index, counter)) counter_handle = win32pdh.AddCounter( query_handle, path) display_counter(counter_handle) # Only need information from one instance break break else: header = 'Counters' echo_info(header) echo_info('=' * len(header)) for counter in counters: path = win32pdh.MakeCounterPath( (None, counterset, None, None, 0, counter)) if win32pdh.ValidatePath(path) != 0: echo_info(f'--> {counter}') echo_info(' Error: no current instances') continue counter_handle = win32pdh.AddCounter(query_handle, path) display_counter(counter_handle) finally: win32pdh.CloseQuery(query_handle)
def extract(self): def getQueryValue(data,key): if key in data: return data[key] else: return None paths = [ ('cpu-total','Processor','_Total','% Processor Time'), ('cpu-us','Processor','_Total','% User Time'), ('cpu-sy','Processor','_Total','% Privileged Time'), ('cpu-r','System',None,'Processor Queue Length'), ('mem-free','Memory',None,'Available Mbytes'), ('mem-pages-ps','Memory',None,'Pages/sec'), ('disk-readtime','PhysicalDisk','_Total','% Disk Read Time'), ('disk-writetime','PhysicalDisk','_Total','% Disk Write Time'), ('disk-queue','PhysicalDisk','_Total','Current Disk Queue Length'), ('disk-rbps','PhysicalDisk','_Total','Disk Read Bytes/sec'), ('disk-wbps','PhysicalDisk','_Total','Disk Write Bytes/sec'), ('disk-rps','PhysicalDisk','_Total','Disk Reads/sec'), ('disk-wps','PhysicalDisk','_Total','Disk Writes/sec'), ('sql-qps','SQLServer:SQL Statistics',None,'Batch Requests/sec'), ('sql-tps','SQLServer:Databases','_Total','Transactions/sec'), ('sql-connections','SQLServer:General Statistics',None,'User Connections'), ('sql-fullscans','SQLServer:Access Methods',None,'Full Scans/sec'), ('sql-targetmemory','SQLServer:Memory Manager',None,'Target Server Memory (KB)'), ('sql-totalmemory','SQLServer:Memory Manager',None,'Total Server Memory (KB)'), ('sql-dataspace','SQLServer:Databases','_Total','Data File(s) Size (KB)'), ('sql-logspace','SQLServer:Databases','_Total','Log File(s) Size (KB)'), ('sql-cachehitratio','SQLServer:Buffer Manager',None,'Buffer cache hit ratio'), ('ws-bps','Web Service','_Total','Bytes Total/sec'), ('ws-rps','Web Service','_Total','Total Method Requests/sec'), ('ws-connections','Web Service','_Total','Current Connections') #('ni-bps','Network Interface','_Total','Bytes Total/sec') ] counters, instances = win32pdh.EnumObjectItems(None, None, 'Network Interface', win32pdh.PERF_DETAIL_WIZARD) #print instances for i, n in enumerate(instances): paths.append( ('ni-bps' + str(i),'Network Interface',n,'Bytes Total/sec') ) #print paths counters = {} base = win32pdh.OpenQuery() #print base for path in paths: counterPath = win32pdh.MakeCounterPath( (None,path[1],path[2], None, -1, path[3]) ) if win32pdh.ValidatePath(counterPath) == 0: #print path counter = win32pdh.AddCounter(base, counterPath) #print counter counters[path[0]] = counter #else: #print path[0], '------path is not valid' # collect the data for the query object. We need to collect the query data # twice to be able to calculate the % Processor Time win32pdh.CollectQueryData(base) set1 = self.getProcess() time.sleep(1) win32pdh.CollectQueryData(base) queryData = {} nibps = 0 # Get the formatted value of the counter for key in counters.keys(): if key.find('ni-bps') == 0: nibps += win32pdh.GetFormattedCounterValue(counters[key],win32pdh.PDH_FMT_LONG)[1] else: queryData[key] = win32pdh.GetFormattedCounterValue(counters[key],win32pdh.PDH_FMT_LONG)[1] queryData['ni-bps'] = nibps win32pdh.CloseQuery(base) info = {} cpu = {} cpu["us"] = getQueryValue(queryData,"cpu-us") cpu["sy"] = getQueryValue(queryData,"cpu-sy") cpu["id"] = 100 - float(getQueryValue(queryData,"cpu-total")) cpu["r"] = getQueryValue(queryData,"cpu-r") memory = {} memory["free"] = getQueryValue(queryData,"mem-free") memory["pages-ps"] = getQueryValue(queryData,"mem-pages-ps") disk = {} disk["readtime"] = getQueryValue(queryData,"disk-readtime") disk["writetime"] = getQueryValue(queryData,"disk-writetime") disk["queue"] = getQueryValue(queryData,"disk-queue") disk["rbps"] = getQueryValue(queryData,"disk-rbps") disk["wbps"] = getQueryValue(queryData,"disk-wbps") disk["bps"] = disk["rbps"] + disk["wbps"] disk["rps"] = getQueryValue(queryData,"disk-rps") disk["wps"] = getQueryValue(queryData,"disk-wps") disk["iops"] = disk["rps"] + disk["wps"] freespace,disksize = self.getDiskSize() #print freespace,disksize if(disksize > 0): disk["size"] = disksize/(1024*1024) disk["used"] = (disksize - freespace) / (1024*1024) disk["use"] = disk["used"] * 100 / disk["size"] if("sql-qps" in queryData): database = {} sqlserver = {} sqlserver["qps"] = getQueryValue(queryData,"sql-qps") sqlserver["tps"] = getQueryValue(queryData,"sql-tps") sqlserver["connections"] = getQueryValue(queryData,"sql-connections") sqlserver["fullscans"] = getQueryValue(queryData,"sql-fullscans") sqlserver["targetmemory"] = getQueryValue(queryData,"sql-targetmemory") sqlserver["totalmemory"] = getQueryValue(queryData,"sql-totalmemory") sqlserver["dataspace"] = getQueryValue(queryData,"sql-dataspace") sqlserver["logspace"] = getQueryValue(queryData,"sql-logspace") sqlserver["cachehitratio"] = getQueryValue(queryData,"sql-cachehitratio") database["sqlserver"] = sqlserver info["database"] = database webserver = {} iis = {} if("ws-bps" in queryData): iis["bps"] = getQueryValue(queryData,"ws-bps") iis["rps"] = getQueryValue(queryData,"ws-rps") iis["connections"] = getQueryValue(queryData,"ws-connections") #iis["requestqueued"] = float(result[col+3]) #+ float(result[col+4]) webserver['iis'] = iis info["webserver"] = webserver network = {} network["bps"] = getQueryValue(queryData,"ni-bps") process = [] set2 = self.getProcess() #self.logger.debug(set1) #self.logger.debug(set2) totaltime = set2['total'] - set1['total'] for s in set1: if s == 'total' : continue if(set2.has_key(s)): proc = {} proc["pid"] = s if totaltime > 0: proc["cpu"] = (sum(set2[s][0:2]) - sum(set1[s][0:2]) )* 100 / totaltime else: proc["cpu"] = 0 proc["mem"] = set2[s][2] proc["mem2"] = set2[s][3] proc["name"] = set2[s][4] proc["command"] = set2[s][5] process.append(proc) process = sorted(process, key=lambda d: d["cpu"]) if len(process) > 10: process = process[-11:] info["infoid"] = str(uuid.uuid1()) info["machineid"] = str(uuid.getnode()) info["timestamp"] = time.strftime("%Y%m%d%H%M%S", time.localtime()) info["os"] = "windows" info["appkey"] = self.AppKey info["cpu"] = cpu info["memory"] = memory info["disk"] = disk info["network"] = network info["process"] = process self.val["info"] = info #pythoncom.CoUninitialize() return self.val
def _configure_counters(self, available_counters, available_instances): if not available_counters: return if self.use_localized_counters: # https://docs.microsoft.com/en-us/windows/win32/api/pdh/nf-pdh-pdhaddcountera # https://mhammond.github.io/pywin32/win32pdh__AddCounter_meth.html counter_selector = win32pdh.AddCounter else: # https://docs.microsoft.com/en-us/windows/win32/api/pdh/nf-pdh-pdhaddenglishcountera # https://mhammond.github.io/pywin32/win32pdh__AddEnglishCounter_meth.html counter_selector = win32pdh.AddEnglishCounter if available_instances: counter_type = MultiCounter self.has_multiple_instances = True else: possible_path = construct_counter_path( machine_name=self.connection.server, object_name=self.name, counter_name=available_counters[0] ) # https://docs.microsoft.com/en-us/windows/win32/api/pdh/nf-pdh-pdhvalidatepatha # https://mhammond.github.io/pywin32/win32pdh__ValidatePath_meth.html if win32pdh.ValidatePath(possible_path) == 0: counter_type = SingleCounter self.has_multiple_instances = False # Multi-instance counter with no instances presently else: counter_type = MultiCounter self.has_multiple_instances = True tag_name = self.tag_name if self.has_multiple_instances: if not tag_name: tag_name = 'instance' else: if tag_name: self._log_multi_instance_option_defined('tag_name') if self.include_pattern is not None: self._log_multi_instance_option_defined('include') if self.exclude_pattern.pattern.count('|') > 0: self._log_multi_instance_option_defined('exclude') if ( self.instance_count_total_metric or self.instance_count_monitored_metric or self.instance_count_unique_metric ): self._log_multi_instance_option_defined('instance_counts') custom_transformers = self.get_custom_transformers() counters = {} for i, entry in enumerate(self.counters_config, 1): if not isinstance(entry, dict): raise ConfigTypeError( f'Entry #{i} of option `counters` for performance object `{self.name}` must be a mapping' ) for counter_name, counter_config in entry.items(): if isinstance(counter_config, str): counter_config = {'name': counter_config} elif not isinstance(counter_config, dict): raise ConfigTypeError( f'Counter `{counter_name}` for performance object `{self.name}` must be a string or mapping' ) elif counter_name in counters: raise ConfigValueError( f'Counter `{counter_name}` for performance object `{self.name}` is already defined' ) if counter_type is SingleCounter: counters[counter_name] = counter_type( counter_name, counter_config, self.check, self.connection, self.name, self.metric_prefix, counter_selector, self.tags, custom_transformers.get(counter_name), ) else: counters[counter_name] = counter_type( counter_name, counter_config, self.check, self.connection, self.name, self.metric_prefix, counter_selector, self.tags, custom_transformers.get(counter_name), tag_name, ) self.counters.extend(counters.values())