Skip to content

Commit

Permalink
[Windows] fix pdh counters on localized versions of windows (#3713)
Browse files Browse the repository at this point in the history
  • Loading branch information
derekwbrown authored Mar 20, 2018
1 parent 64a7b15 commit 9501ade
Showing 1 changed file with 59 additions and 10 deletions.
69 changes: 59 additions & 10 deletions checks/libs/win/winpdh.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Unless explicitly stated otherwise all files in this repository are licensed
# under the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2017 Datadog, Inc.
# Copyright 2018 Datadog, Inc.

from collections import defaultdict
import time
import win32pdh
import _winreg
Expand All @@ -13,16 +14,23 @@
SINGLE_INSTANCE_KEY = "__single_instance"
class WinPDHCounter(object):
# store the dictionary of pdh counter names
pdh_counter_dict = {}
pdh_counter_dict = defaultdict(list)

def __init__(self, class_name, counter_name, log, instance_name = None, machine_name = None, precision=None):
self.logger = log
self._get_counter_dictionary()
self._class_name = win32pdh.LookupPerfNameByIndex(None, int(WinPDHCounter.pdh_counter_dict[class_name]))
self._counter_name = win32pdh.LookupPerfNameByIndex(None, int(WinPDHCounter.pdh_counter_dict[counter_name]))
class_name_index_list = WinPDHCounter.pdh_counter_dict[class_name]
if len(class_name_index_list) == 0:
self.logger.warn("Class %s was not in counter name list, attempting english counter" % class_name)
self._class_name = class_name
else:
if len(class_name_index_list) > 1:
self.logger.warn("Class %s had multiple (%d) indices, using first" % (class_name, len(class_name_index_list)))
self._class_name = win32pdh.LookupPerfNameByIndex(None, int(class_name_index_list[0]))

self._is_single_instance = False
self.hq = win32pdh.OpenQuery()
self.logger = log

self.counterdict = {}
if precision is None:
self._precision = win32pdh.PDH_FMT_DOUBLE
Expand All @@ -31,7 +39,7 @@ def __init__(self, class_name, counter_name, log, instance_name = None, machine_
counters, instances = win32pdh.EnumObjectItems(None, machine_name, self._class_name, win32pdh.PERF_DETAIL_WIZARD)
if instance_name is None and len(instances) > 0:
for inst in instances:
path = win32pdh.MakeCounterPath((machine_name, self._class_name, inst, None, 0, self._counter_name))
path = self._make_counter_path(machine_name, counter_name, inst, counters)
try:
self.counterdict[inst] = win32pdh.AddCounter(self.hq, path)
except:
Expand All @@ -57,7 +65,7 @@ def __init__(self, class_name, counter_name, log, instance_name = None, machine_
instance_name, class_name
))
return
path = win32pdh.MakeCounterPath((machine_name, self._class_name, instance_name, None, 0, self._counter_name))
path = self._make_counter_path(machine_name, counter_name, instance_name, counters)
try:
self.logger.debug("Path: %s\n" % unicode(path))
except:
Expand Down Expand Up @@ -97,7 +105,6 @@ def get_all_values(self):

for inst, counter_handle in self.counterdict.iteritems():
try:
self.logger.info("Getting %s %d" % (inst, self._precision))
t, val = win32pdh.GetFormattedCounterValue(counter_handle, self._precision)
ret[inst] = val
except Exception as e:
Expand Down Expand Up @@ -142,6 +149,48 @@ def _get_counter_dictionary(self):
idx = 0
idx_max = len(val)
while idx < idx_max:
# counter index is idx + 1, counter name is ids
WinPDHCounter.pdh_counter_dict[val[idx+1]] = val[idx]
# counter index is idx , counter name is idx + 1
WinPDHCounter.pdh_counter_dict[val[idx+1]].append(val[idx])
idx += 2

def _make_counter_path(self, machine_name, counter_name, instance_name, counters):
'''
When handling non english versions, the counters don't work quite as documented.
This is because strings like "Bytes Sent/sec" might appear multiple times in the
english master, and might not have mappings for each index.
Search each index, and make sure the requested counter name actually appears in
the list of available counters; that's the counter we'll use.
'''
counter_name_index_list = WinPDHCounter.pdh_counter_dict[counter_name]
path = ""
for index in counter_name_index_list:
c = win32pdh.LookupPerfNameByIndex(None, int(index))
if c is None or len(c) == 0:
self.logger.debug("Index %s not found, skipping" % index)
continue

# check to see if this counter is in the list of counters for this class
if c not in counters:
try:
self.logger.debug("Index %s counter %s not in counter list" % (index, unicode(c)))
except:
# some unicode characters are not translatable here. Don't fail just
# because we couldn't log
self.logger.debug("Index %s not in counter list" % index)
pass

continue

# see if we can create a counter
try:
path = win32pdh.MakeCounterPath((machine_name, self._class_name, instance_name, None, 0, c))
self.logger.debug("Successfully created path %s" % index)
break
except:
try:
self.logger.info("Unable to make path with counter %s, trying next available" % unicode(c))
except:
self.logger.info("Unable to make path with counter index %s, trying next available" % index)
pass
return path

0 comments on commit 9501ade

Please sign in to comment.