1
1
# Unless explicitly stated otherwise all files in this repository are licensed
2
2
# under the Apache License Version 2.0.
3
3
# This product includes software developed at Datadog (https://www.datadoghq.com/).
4
- # Copyright 2017 Datadog, Inc.
4
+ # Copyright 2018 Datadog, Inc.
5
5
6
+ from collections import defaultdict
6
7
import time
7
8
import win32pdh
8
9
import _winreg
13
14
SINGLE_INSTANCE_KEY = "__single_instance"
14
15
class WinPDHCounter (object ):
15
16
# store the dictionary of pdh counter names
16
- pdh_counter_dict = {}
17
+ pdh_counter_dict = defaultdict ( list )
17
18
18
19
def __init__ (self , class_name , counter_name , log , instance_name = None , machine_name = None , precision = None ):
20
+ self .logger = log
19
21
self ._get_counter_dictionary ()
20
- self ._class_name = win32pdh .LookupPerfNameByIndex (None , int (WinPDHCounter .pdh_counter_dict [class_name ]))
21
- self ._counter_name = win32pdh .LookupPerfNameByIndex (None , int (WinPDHCounter .pdh_counter_dict [counter_name ]))
22
+ class_name_index_list = WinPDHCounter .pdh_counter_dict [class_name ]
23
+ if len (class_name_index_list ) == 0 :
24
+ self .logger .warn ("Class %s was not in counter name list, attempting english counter" % class_name )
25
+ self ._class_name = class_name
26
+ else :
27
+ if len (class_name_index_list ) > 1 :
28
+ self .logger .warn ("Class %s had multiple (%d) indices, using first" % (class_name , len (class_name_index_list )))
29
+ self ._class_name = win32pdh .LookupPerfNameByIndex (None , int (class_name_index_list [0 ]))
22
30
23
31
self ._is_single_instance = False
24
32
self .hq = win32pdh .OpenQuery ()
25
- self . logger = log
33
+
26
34
self .counterdict = {}
27
35
if precision is None :
28
36
self ._precision = win32pdh .PDH_FMT_DOUBLE
@@ -31,7 +39,7 @@ def __init__(self, class_name, counter_name, log, instance_name = None, machine_
31
39
counters , instances = win32pdh .EnumObjectItems (None , machine_name , self ._class_name , win32pdh .PERF_DETAIL_WIZARD )
32
40
if instance_name is None and len (instances ) > 0 :
33
41
for inst in instances :
34
- path = win32pdh . MakeCounterPath (( machine_name , self . _class_name , inst , None , 0 , self . _counter_name ) )
42
+ path = self . _make_counter_path ( machine_name , counter_name , inst , counters )
35
43
try :
36
44
self .counterdict [inst ] = win32pdh .AddCounter (self .hq , path )
37
45
except :
@@ -57,7 +65,7 @@ def __init__(self, class_name, counter_name, log, instance_name = None, machine_
57
65
instance_name , class_name
58
66
))
59
67
return
60
- path = win32pdh . MakeCounterPath (( machine_name , self . _class_name , instance_name , None , 0 , self . _counter_name ) )
68
+ path = self . _make_counter_path ( machine_name , counter_name , instance_name , counters )
61
69
try :
62
70
self .logger .debug ("Path: %s\n " % unicode (path ))
63
71
except :
@@ -97,7 +105,6 @@ def get_all_values(self):
97
105
98
106
for inst , counter_handle in self .counterdict .iteritems ():
99
107
try :
100
- self .logger .info ("Getting %s %d" % (inst , self ._precision ))
101
108
t , val = win32pdh .GetFormattedCounterValue (counter_handle , self ._precision )
102
109
ret [inst ] = val
103
110
except Exception as e :
@@ -142,6 +149,48 @@ def _get_counter_dictionary(self):
142
149
idx = 0
143
150
idx_max = len (val )
144
151
while idx < idx_max :
145
- # counter index is idx + 1 , counter name is ids
146
- WinPDHCounter .pdh_counter_dict [val [idx + 1 ]] = val [idx ]
152
+ # counter index is idx , counter name is idx + 1
153
+ WinPDHCounter .pdh_counter_dict [val [idx + 1 ]]. append ( val [idx ])
147
154
idx += 2
155
+
156
+ def _make_counter_path (self , machine_name , counter_name , instance_name , counters ):
157
+ '''
158
+ When handling non english versions, the counters don't work quite as documented.
159
+ This is because strings like "Bytes Sent/sec" might appear multiple times in the
160
+ english master, and might not have mappings for each index.
161
+
162
+ Search each index, and make sure the requested counter name actually appears in
163
+ the list of available counters; that's the counter we'll use.
164
+ '''
165
+ counter_name_index_list = WinPDHCounter .pdh_counter_dict [counter_name ]
166
+ path = ""
167
+ for index in counter_name_index_list :
168
+ c = win32pdh .LookupPerfNameByIndex (None , int (index ))
169
+ if c is None or len (c ) == 0 :
170
+ self .logger .debug ("Index %s not found, skipping" % index )
171
+ continue
172
+
173
+ # check to see if this counter is in the list of counters for this class
174
+ if c not in counters :
175
+ try :
176
+ self .logger .debug ("Index %s counter %s not in counter list" % (index , unicode (c )))
177
+ except :
178
+ # some unicode characters are not translatable here. Don't fail just
179
+ # because we couldn't log
180
+ self .logger .debug ("Index %s not in counter list" % index )
181
+ pass
182
+
183
+ continue
184
+
185
+ # see if we can create a counter
186
+ try :
187
+ path = win32pdh .MakeCounterPath ((machine_name , self ._class_name , instance_name , None , 0 , c ))
188
+ self .logger .debug ("Successfully created path %s" % index )
189
+ break
190
+ except :
191
+ try :
192
+ self .logger .info ("Unable to make path with counter %s, trying next available" % unicode (c ))
193
+ except :
194
+ self .logger .info ("Unable to make path with counter index %s, trying next available" % index )
195
+ pass
196
+ return path
0 commit comments