win32-pdh 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/win32/pdh/constants.rb +2 -0
- data/lib/win32/pdh/counter.rb +41 -6
- data/lib/win32/pdh/query.rb +24 -8
- data/lib/win32/pdh.rb +19 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9f57c2db43f6412bceab31740be7f3131752334ff5b9c5f1f41f634519477bd
|
4
|
+
data.tar.gz: 74ea0ab008113496543dc001d947cbe93b3751eef9fb65be219887eb88921b36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b569a0bf0cfe35093c065cb527dc521fc503ff40dc882e35afdbfa8ec4036da16cf5cd7ef7003609406a640f77ae97ca93367119b2105a1b890212493a7edbd
|
7
|
+
data.tar.gz: 14e6def409243a45b3e3a51dbf544f9e5df224cbb32252bd9c13920702ccd05f6029e690932eb07618f970977579b694c58cb7539a78f111ccf7482ed2a85077
|
data/lib/win32/pdh/constants.rb
CHANGED
@@ -104,6 +104,7 @@ module Win32
|
|
104
104
|
PERF_DETAIL_WIZARD = 400
|
105
105
|
ERROR_SUCCESS = 0x00000000
|
106
106
|
|
107
|
+
# Value-to-name map, for reverse lookup.
|
107
108
|
NAMES = {
|
108
109
|
0x00000000 => 'PDH_CSTATUS_VALID_DATA'.freeze,
|
109
110
|
0x00000001 => 'PDH_CSTATUS_NEW_DATA'.freeze,
|
@@ -193,6 +194,7 @@ module Win32
|
|
193
194
|
0xC0000BFE => 'PDH_QUERY_PERF_DATA_TIMEOUT'.freeze,
|
194
195
|
}.freeze
|
195
196
|
|
197
|
+
# Value-to-message hash, for generating messages.
|
196
198
|
MESSAGES = {
|
197
199
|
0x00000000 => 'The returned data is valid.'.freeze,
|
198
200
|
0x00000001 => 'The return data value is valid and different from the last sample.'.freeze,
|
data/lib/win32/pdh/counter.rb
CHANGED
@@ -5,7 +5,12 @@ require 'win32/pdh/constants'
|
|
5
5
|
|
6
6
|
module Win32
|
7
7
|
module Pdh
|
8
|
+
##
|
9
|
+
# Class representing an individual counter.
|
10
|
+
#
|
11
|
+
# This won't usually be created directly, but built using Query#add_counter.
|
8
12
|
class Counter
|
13
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa373041(v=vs.85).aspx
|
9
14
|
class PDH_COUNTER_PATH_ELEMENTS < FFI::Struct
|
10
15
|
layout(
|
11
16
|
:szMachineName, :pointer,
|
@@ -16,6 +21,7 @@ module Win32
|
|
16
21
|
:szCounterName, :pointer,
|
17
22
|
)
|
18
23
|
end
|
24
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa373038(v=vs.85).aspx
|
19
25
|
class PDH_COUNTER_INFO < FFI::Struct
|
20
26
|
layout(
|
21
27
|
:dwLength, :uint,
|
@@ -33,6 +39,7 @@ module Win32
|
|
33
39
|
)
|
34
40
|
end
|
35
41
|
|
42
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa373050(v=vs.85).aspx
|
36
43
|
class PDH_FMT_COUNTERVALUE_VALUE < FFI::Union
|
37
44
|
layout(
|
38
45
|
:longValue, :int32,
|
@@ -43,6 +50,7 @@ module Win32
|
|
43
50
|
)
|
44
51
|
end
|
45
52
|
|
53
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa373050(v=vs.85).aspx
|
46
54
|
class PDH_FMT_COUNTERVALUE < FFI::Struct
|
47
55
|
layout(
|
48
56
|
:CStatus, :uint32,
|
@@ -52,6 +60,9 @@ module Win32
|
|
52
60
|
|
53
61
|
attr_accessor :type, :version, :status, :scale, :default_scale, :full_path, :machine_name, :object_name, :instance_name, :instance_index, :counter_name, :explain_text
|
54
62
|
|
63
|
+
##
|
64
|
+
# Initializes the counter from a query and a path. This usually won't be
|
65
|
+
# called directly, but generated from Query#add_counter
|
55
66
|
def initialize(query:, path:)
|
56
67
|
path = (path + "\0").encode('UTF-16LE')
|
57
68
|
handle_pointer = FFI::MemoryPointer.new(:pointer)
|
@@ -66,6 +77,16 @@ module Win32
|
|
66
77
|
load_info
|
67
78
|
end
|
68
79
|
|
80
|
+
##
|
81
|
+
# Remove the counter from its Query.
|
82
|
+
#
|
83
|
+
# This isn't necessary as a part of general cleanup, as closing a Query
|
84
|
+
# will also clean up all counters. This is necessary if you are doing
|
85
|
+
# long-term management that may need counters added and removed while
|
86
|
+
# running. So if you're using a Query as a one-off and it is being closed
|
87
|
+
# after use, don't bother with this. If you are keeping a single query
|
88
|
+
# open long-term, make sure you use this when necessary, otherwise you
|
89
|
+
# will leak memory.
|
69
90
|
def remove
|
70
91
|
# Only allow removing once
|
71
92
|
unless @handle.nil?
|
@@ -105,12 +126,20 @@ module Win32
|
|
105
126
|
Pdh.check_status @status
|
106
127
|
end
|
107
128
|
|
108
|
-
|
109
|
-
@status == Constants::ERROR_SUCCESS
|
110
|
-
end
|
129
|
+
private :load_info
|
111
130
|
|
131
|
+
##
|
112
132
|
# Get the PDH_FMT_COUNTERVALUE_VALUE given the format, checking status and
|
113
|
-
# raising an exception if necessary
|
133
|
+
# raising an exception if necessary.
|
134
|
+
#
|
135
|
+
# Usually, you won't use this directly; you'd use #get_double, #get_long,
|
136
|
+
# or #get_large to get the formatted value without any hassle.
|
137
|
+
#
|
138
|
+
# Will raise a PdhError if the value is bad (if you've only run
|
139
|
+
# Query#collect_query_data once, but this counter requires a history to
|
140
|
+
# calculate a rate, this will raise an exception. Be careful, and
|
141
|
+
# probably wrap all calls to this in an exception block that takes into
|
142
|
+
# account the possibility of a counter failing to get a value)
|
114
143
|
def get(format)
|
115
144
|
value = PDH_FMT_COUNTERVALUE.new
|
116
145
|
status = PdhFFI.PdhGetFormattedCounterValue(
|
@@ -125,19 +154,25 @@ module Win32
|
|
125
154
|
end
|
126
155
|
|
127
156
|
##
|
128
|
-
# Get value as a double
|
157
|
+
# Get value as a double.
|
158
|
+
#
|
159
|
+
# This uses #get, so read the notes in there about exception raising.
|
129
160
|
def get_double
|
130
161
|
get(Constants::PDH_FMT_DOUBLE)[:doubleValue]
|
131
162
|
end
|
132
163
|
|
133
164
|
##
|
134
|
-
# Get value as a 64-bit integer
|
165
|
+
# Get value as a 64-bit integer.
|
166
|
+
#
|
167
|
+
# This uses #get, so read the notes in there about exception raising.
|
135
168
|
def get_large
|
136
169
|
get(Constants::PDH_FMT_LARGE)[:largeValue]
|
137
170
|
end
|
138
171
|
|
139
172
|
##
|
140
173
|
# Get value as a 32-bit integer
|
174
|
+
#
|
175
|
+
# This uses #get, so read the notes in there about exception raising.
|
141
176
|
def get_long
|
142
177
|
get(Constants::PDH_FMT_LONG)[:longValue]
|
143
178
|
end
|
data/lib/win32/pdh/query.rb
CHANGED
@@ -3,6 +3,8 @@ require 'win32/pdh/counter'
|
|
3
3
|
|
4
4
|
module Win32
|
5
5
|
module Pdh
|
6
|
+
##
|
7
|
+
# Class representing a Query, and holding a query handle.
|
6
8
|
class Query
|
7
9
|
def initialize(source=nil)
|
8
10
|
source =
|
@@ -13,7 +15,7 @@ module Win32
|
|
13
15
|
end
|
14
16
|
handle_pointer = FFI::MemoryPointer.new(:pointer)
|
15
17
|
status = PdhFFI.PdhOpenQueryW(source, FFI::Pointer::NULL, handle_pointer)
|
16
|
-
|
18
|
+
Pdh.check_status status
|
17
19
|
@handle = handle_pointer.read_pointer
|
18
20
|
end
|
19
21
|
|
@@ -21,18 +23,20 @@ module Win32
|
|
21
23
|
# Only allow closing once
|
22
24
|
unless @handle.nil?
|
23
25
|
status = PdhFFI.PdhCloseQuery(@handle)
|
24
|
-
|
26
|
+
Pdh.check_status status
|
25
27
|
@handle = nil
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
31
|
##
|
30
|
-
# Simple query opening function.
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
32
|
+
# Simple query opening function.
|
33
|
+
#
|
34
|
+
# Uses the OpenQuery function and gets a query, passes it into the block,
|
35
|
+
# and then closes it afterward. If no block is given, it just returns the
|
36
|
+
# query, and you are responsible for closing it. The GC will not close
|
37
|
+
# this for you, so you can easily leak resources. It's strongly
|
38
|
+
# recommended to use the block style if at all possible to ensure resource
|
39
|
+
# cleanup.
|
36
40
|
def self.open(source=nil)
|
37
41
|
query = new source
|
38
42
|
if block_given?
|
@@ -46,12 +50,18 @@ module Win32
|
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
53
|
+
##
|
54
|
+
# Simple wrapper around PdhIsRealTimeQuery.
|
55
|
+
#
|
56
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa372646(v=vs.85).aspx
|
49
57
|
def real_time?
|
50
58
|
PdhFFI.PdhIsRealTimeQuery(@handle) == :true
|
51
59
|
end
|
52
60
|
|
53
61
|
##
|
54
62
|
# Adds a counter to this query and return it as a Counter object.
|
63
|
+
#
|
64
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa372204(v=vs.85).aspx
|
55
65
|
def add_counter(path)
|
56
66
|
Counter.new(
|
57
67
|
query: @handle,
|
@@ -59,6 +69,12 @@ module Win32
|
|
59
69
|
)
|
60
70
|
end
|
61
71
|
|
72
|
+
##
|
73
|
+
# Calls PdhCollectQueryData. This is necessary to load counters with data
|
74
|
+
# before retreiving it.
|
75
|
+
#
|
76
|
+
# Some counters may need this called twice before they can retreive the
|
77
|
+
# data. CPU counters are obvious examples.
|
62
78
|
def collect_query_data
|
63
79
|
status = PdhFFI.PdhCollectQueryData(@handle)
|
64
80
|
Pdh.check_status status
|
data/lib/win32/pdh.rb
CHANGED
@@ -4,6 +4,9 @@ require 'ffi'
|
|
4
4
|
|
5
5
|
module Win32
|
6
6
|
module Pdh
|
7
|
+
##
|
8
|
+
# Simple error subclass. Currently, this is what type all exceptions
|
9
|
+
# directly raised by this library are.
|
7
10
|
class PdhError < StandardError
|
8
11
|
def initialize(status)
|
9
12
|
super("PDH error #{Constants::NAMES[status]}: #{Constants::MESSAGES[status]}")
|
@@ -36,6 +39,8 @@ module Win32
|
|
36
39
|
array.pack('n*').force_encoding('UTF-16BE').encode('UTF-8')
|
37
40
|
end
|
38
41
|
|
42
|
+
##
|
43
|
+
# Container namespace for all Pdh functions.
|
39
44
|
module PdhFFI
|
40
45
|
extend FFI::Library
|
41
46
|
ffi_lib 'Pdh.dll'
|
@@ -69,12 +74,14 @@ module Win32
|
|
69
74
|
|
70
75
|
##
|
71
76
|
# Uses PdhEnumObjects to enumerate objects at the given target. Returns the
|
72
|
-
# objects as
|
77
|
+
# objects as an array of strings.
|
78
|
+
#
|
79
|
+
# PdhEnumObjects: https://msdn.microsoft.com/en-us/library/windows/desktop/aa372600(v=vs.85).aspx
|
73
80
|
#
|
74
81
|
# Params:
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
82
|
+
# source:: The same as szDataSource
|
83
|
+
# machine:: The same as szMachineName
|
84
|
+
# detail:: Alias for dwDetailLevel, as a symbol. May be :novice, :advanced, :expert, or :wizard. Defaults to :novice.
|
78
85
|
def self.enum_objects(source: nil, machine: nil, detail: :novice)
|
79
86
|
source =
|
80
87
|
if source.nil?
|
@@ -125,11 +132,15 @@ module Win32
|
|
125
132
|
string.split("\0")
|
126
133
|
end
|
127
134
|
|
135
|
+
##
|
136
|
+
# Structure of instances and counters, for ::enum_object_items
|
128
137
|
ItemEnum = Struct.new('ItemEnum', :instances, :counters)
|
129
138
|
|
130
139
|
##
|
131
140
|
# Enumerates an object's counter and instance names. Returns an ItemEnum
|
132
141
|
# with the results.
|
142
|
+
#
|
143
|
+
# Uses PdhEnumObjectItems: https://msdn.microsoft.com/en-us/library/windows/desktop/aa372595(v=vs.85).aspx
|
133
144
|
def self.enum_object_items(object:, source: nil, machine: nil, detail: :novice)
|
134
145
|
object = (object + "\0").encode('UTF-16LE')
|
135
146
|
source =
|
@@ -194,6 +205,10 @@ module Win32
|
|
194
205
|
|
195
206
|
##
|
196
207
|
# Expands a wildcard path into all matching counter paths.
|
208
|
+
#
|
209
|
+
# Returns a frozen array of frozen strings.
|
210
|
+
#
|
211
|
+
# Uses PdhExpandWildCardPath: https://msdn.microsoft.com/en-us/library/windows/desktop/aa372606(v=vs.85).aspx
|
197
212
|
def self.expand_wildcards(path:, source: nil, expand_counters: true, expand_instances: true)
|
198
213
|
path = (path + "\0").encode('UTF-16LE')
|
199
214
|
source =
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win32-pdh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Taylor C. Richberger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|