fluent-plugin-windows-exporter 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +202 -0
- data/README.md +77 -0
- data/lib/fluent/plugin/hkey_perf_data_converted_type.rb +148 -0
- data/lib/fluent/plugin/hkey_perf_data_raw_type.rb +143 -0
- data/lib/fluent/plugin/hkey_perf_data_reader.rb +431 -0
- data/lib/fluent/plugin/in_windows_exporter.rb +882 -0
- data/lib/fluent/plugin/test_hpd_reader.rb +124 -0
- data/lib/fluent/plugin/winffi.rb +164 -0
- metadata +129 -0
@@ -0,0 +1,882 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2021- Fujimoto Seiji, Fukuda Daijiro
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require "fluent/plugin/input"
|
17
|
+
require_relative "winffi"
|
18
|
+
require_relative "hkey_perf_data_reader"
|
19
|
+
|
20
|
+
module Fluent
|
21
|
+
module Plugin
|
22
|
+
module Constants
|
23
|
+
# https://github.com/prometheus-community/windows_exporter/blob/master/collector/collector.go
|
24
|
+
TICKS_TO_SECONDS_SCALE_FACTOR = 1 / 1e7
|
25
|
+
WINDOWS_EPOCH = 116444736000000000
|
26
|
+
|
27
|
+
# https://github.com/leoluk/perflib_exporter/blob/master/collector/mapper.go
|
28
|
+
# These flag values may be composed of the base flags in winperf.h.
|
29
|
+
# ref: https://github.com/Kochise/Picat-win32/blob/master/emu/windows/winperf.h
|
30
|
+
PERF_ELAPSED_TIME = 0x30240500
|
31
|
+
PERF_100NSEC_TIMER = 0x20510500
|
32
|
+
PERF_PRECISION_100NS_TIMER = 0x20570500
|
33
|
+
end
|
34
|
+
|
35
|
+
class WindowsExporterInput < Fluent::Plugin::Input
|
36
|
+
include Constants
|
37
|
+
|
38
|
+
Fluent::Plugin.register_input("windows_exporter", self)
|
39
|
+
|
40
|
+
helpers :timer
|
41
|
+
|
42
|
+
desc "Tag of the output events"
|
43
|
+
config_param :tag, :string, default: "windows.metrics"
|
44
|
+
desc "The interval time between data collection"
|
45
|
+
config_param :scrape_interval, :time, default: 60
|
46
|
+
desc "Enable cpu collector"
|
47
|
+
config_param :cpu, :bool, default: true
|
48
|
+
desc "Enable disk collector"
|
49
|
+
config_param :logical_disk, :bool, default: true
|
50
|
+
desc "Enable memory collector"
|
51
|
+
config_param :memory, :bool, default: true
|
52
|
+
desc "Enable network collector"
|
53
|
+
config_param :net, :bool, default: true
|
54
|
+
desc "Enable OS collector"
|
55
|
+
config_param :os, :bool, default: true
|
56
|
+
|
57
|
+
def configure(conf)
|
58
|
+
super
|
59
|
+
@cache_manager = CacheManager.new
|
60
|
+
|
61
|
+
@collectors = []
|
62
|
+
@collectors << method(:collect_cpu) if @cpu
|
63
|
+
@collectors << method(:collect_logical_disk) if @logical_disk
|
64
|
+
@collectors << method(:collect_memory) if @memory
|
65
|
+
@collectors << method(:collect_net) if @net
|
66
|
+
@collectors << method(:collect_os) if @os
|
67
|
+
end
|
68
|
+
|
69
|
+
def start
|
70
|
+
super
|
71
|
+
timer_execute(:in_windows_exporter, @scrape_interval, &method(:on_timer))
|
72
|
+
$log.info("Start in_windows_exporter (%i collectors, every %is)" % [@collectors.count, @scrape_interval])
|
73
|
+
end
|
74
|
+
|
75
|
+
def shutdown
|
76
|
+
super
|
77
|
+
end
|
78
|
+
|
79
|
+
def on_timer
|
80
|
+
now = Fluent::EventTime.now
|
81
|
+
update_cache()
|
82
|
+
$log.debug("Updated Windows counters (%.2fs)" % (Fluent::EventTime.now.to_f - now.to_f))
|
83
|
+
|
84
|
+
es = Fluent::MultiEventStream.new
|
85
|
+
for method in @collectors do
|
86
|
+
begin
|
87
|
+
for record in method.call() do
|
88
|
+
es.add(now, record)
|
89
|
+
end
|
90
|
+
rescue => e
|
91
|
+
$log.error(e.message)
|
92
|
+
$log.error_backtrace
|
93
|
+
end
|
94
|
+
end
|
95
|
+
router.emit_stream(@tag, es)
|
96
|
+
end
|
97
|
+
|
98
|
+
def update_cache
|
99
|
+
@cache_manager.update
|
100
|
+
end
|
101
|
+
|
102
|
+
def collect_cpu
|
103
|
+
hpd = @cache_manager.hkey_perf_data_cache
|
104
|
+
counterset_name = "Processor Information"
|
105
|
+
unless hpd.key?(counterset_name)
|
106
|
+
$log.warn("Could not get HKeyPerfData CounterSet: #{counterset_name}")
|
107
|
+
return []
|
108
|
+
end
|
109
|
+
|
110
|
+
records = []
|
111
|
+
for core in hpd[counterset_name].instances do
|
112
|
+
if core.name.downcase.include?("_total")
|
113
|
+
next
|
114
|
+
end
|
115
|
+
records += [
|
116
|
+
{
|
117
|
+
"type" => "counter",
|
118
|
+
"name" => "windows_cpu_cstate_seconds_total",
|
119
|
+
"desc" => "Time spent in low-power idle state",
|
120
|
+
"labels" => {"core" => core.name, "state" => "c1" },
|
121
|
+
"value" => core.counters["% C1 Time"].value
|
122
|
+
},
|
123
|
+
{
|
124
|
+
"type" => "counter",
|
125
|
+
"name" => "windows_cpu_cstate_seconds_total",
|
126
|
+
"desc" => "Time spent in low-power idle state",
|
127
|
+
"labels" => {"core" => core.name, "state" => "c2" },
|
128
|
+
"value" => core.counters["% C2 Time"].value
|
129
|
+
},
|
130
|
+
{
|
131
|
+
"type" => "counter",
|
132
|
+
"name" => "windows_cpu_cstate_seconds_total",
|
133
|
+
"desc" => "Time spent in low-power idle state",
|
134
|
+
"labels" => {"core" => core.name, "state" => "c3" },
|
135
|
+
"value" => core.counters["% C3 Time"].value
|
136
|
+
},
|
137
|
+
{
|
138
|
+
"type" => "counter",
|
139
|
+
"name" => "windows_cpu_time_total",
|
140
|
+
"desc" => "Time that processor spent in different modes (idle, user, system, ...)",
|
141
|
+
"labels" => {"core" => core.name, "mode" => "idle"},
|
142
|
+
"value" => core.counters["% Idle Time"].value
|
143
|
+
},
|
144
|
+
{
|
145
|
+
"type" => "counter",
|
146
|
+
"name" => "windows_cpu_time_total",
|
147
|
+
"desc" => "Time that processor spent in different modes (idle, user, system, ...)",
|
148
|
+
"labels" => {"core" => core.name, "mode" => "interrupt"},
|
149
|
+
"value" => core.counters["% Interrupt Time"].value
|
150
|
+
},
|
151
|
+
{
|
152
|
+
"type" => "counter",
|
153
|
+
"name" => "windows_cpu_time_total",
|
154
|
+
"desc" => "Time that processor spent in different modes (idle, user, system, ...)",
|
155
|
+
"labels" => {"core" => core.name, "mode" => "dpc"},
|
156
|
+
"value" => core.counters["% DPC Time"].value
|
157
|
+
},
|
158
|
+
{
|
159
|
+
"type" => "counter",
|
160
|
+
"name" => "windows_cpu_time_total",
|
161
|
+
"desc" => "Time that processor spent in different modes (idle, user, system, ...)",
|
162
|
+
"labels" => {"core" => core.name, "mode" => "privileged"},
|
163
|
+
"value" => core.counters["% Privileged Time"].value
|
164
|
+
},
|
165
|
+
{
|
166
|
+
"type" => "counter",
|
167
|
+
"name" => "windows_cpu_time_total",
|
168
|
+
"desc" => "Time that processor spent in different modes (idle, user, system, ...)",
|
169
|
+
"labels" => {"core" => core.name, "mode" => "user"},
|
170
|
+
"value" => core.counters["% User Time"].value
|
171
|
+
},
|
172
|
+
{
|
173
|
+
"type" => "counter",
|
174
|
+
"name" => "windows_cpu_interrupts_total",
|
175
|
+
"desc" => "Total number of received and serviced hardware interrupts",
|
176
|
+
"labels" => {"core" => core.name},
|
177
|
+
"value" => core.counters["Interrupts/sec"].value
|
178
|
+
},
|
179
|
+
{
|
180
|
+
"type" => "counter",
|
181
|
+
"name" => "windows_cpu_dpcs_total",
|
182
|
+
"desc" => "Total number of received and serviced deferred procedure calls (DPCs)",
|
183
|
+
"labels" => {"core" => core.name},
|
184
|
+
"value" => core.counters["DPCs Queued/sec"].value
|
185
|
+
},
|
186
|
+
{
|
187
|
+
"type" => "counter",
|
188
|
+
"name" => "windows_cpu_clock_interrupts_total",
|
189
|
+
"desc" => "Total number of received and serviced clock tick interrupts",
|
190
|
+
"labels" => {"core" => core.name},
|
191
|
+
"value" => core.counters["Clock Interrupts/sec"].value
|
192
|
+
},
|
193
|
+
{
|
194
|
+
"type" => "counter",
|
195
|
+
"name" => "windows_cpu_idle_break_events_total",
|
196
|
+
"desc" => "Total number of time processor was woken from idle",
|
197
|
+
"labels" => {"core" => core.name},
|
198
|
+
"value" => core.counters["Idle Break Events/sec"].value
|
199
|
+
},
|
200
|
+
{
|
201
|
+
"type" => "gauge",
|
202
|
+
"name" => "windows_cpu_parking_status",
|
203
|
+
"desc" => "Parking Status represents whether a processor is parked or not",
|
204
|
+
"labels" => {"core" => core.name},
|
205
|
+
"value" => core.counters["Parking Status"].value
|
206
|
+
},
|
207
|
+
{
|
208
|
+
"type" => "gauge",
|
209
|
+
"name" => "windows_cpu_core_frequency_mhz",
|
210
|
+
"desc" => "Core frequency in megahertz",
|
211
|
+
"labels" => {"core" => core.name},
|
212
|
+
"value" => core.counters["Processor Frequency"].value
|
213
|
+
},
|
214
|
+
{
|
215
|
+
"type" => "gauge",
|
216
|
+
"name" => "windows_cpu_processor_performance",
|
217
|
+
"desc" => "Processor Performance is the average performance of the processor while it is executing instructions, as a percentage of the nominal performance of the processor. On some processors, Processor Performance may exceed 100%",
|
218
|
+
"labels" => {"core" => core.name},
|
219
|
+
"value" => core.counters["% Processor Performance"].value
|
220
|
+
}
|
221
|
+
]
|
222
|
+
end
|
223
|
+
return records
|
224
|
+
end
|
225
|
+
|
226
|
+
def collect_logical_disk
|
227
|
+
hpd = @cache_manager.hkey_perf_data_cache
|
228
|
+
counterset_name = "LogicalDisk"
|
229
|
+
unless hpd.key?(counterset_name)
|
230
|
+
$log.warn("Could not get HKeyPerfData CounterSet: #{counterset_name}")
|
231
|
+
return []
|
232
|
+
end
|
233
|
+
|
234
|
+
records = []
|
235
|
+
for volume in hpd[counterset_name].instances do
|
236
|
+
if volume.name.downcase.include?("_total")
|
237
|
+
next
|
238
|
+
end
|
239
|
+
|
240
|
+
records += [
|
241
|
+
{
|
242
|
+
"type" => "gauge",
|
243
|
+
"name" => "windows_logical_disk_requests_queued",
|
244
|
+
"desc" => "Number of requests outstanding on the disk at the time the performance data is collected",
|
245
|
+
"labels" => {"volume" => volume.name},
|
246
|
+
"value" => volume.counters["Current Disk Queue Length"].value
|
247
|
+
},
|
248
|
+
{
|
249
|
+
"type" => "counter",
|
250
|
+
"name" => "windows_logical_disk_read_bytes_total",
|
251
|
+
"desc" => "Rate at which bytes are transferred from the disk during read operations",
|
252
|
+
"labels" => {"volume" => volume.name},
|
253
|
+
"value" => volume.counters["Disk Read Bytes/sec"].value
|
254
|
+
},
|
255
|
+
{
|
256
|
+
"type" => "counter",
|
257
|
+
"name" => "windows_logical_disk_reads_total",
|
258
|
+
"desc" => "Rate of read operations on the disk",
|
259
|
+
"labels" => {"volume" => volume.name},
|
260
|
+
"value" => volume.counters["Disk Reads/sec"].value
|
261
|
+
},
|
262
|
+
{
|
263
|
+
"type" => "counter",
|
264
|
+
"name" => "windows_logical_disk_write_bytes_total",
|
265
|
+
"desc" => "Rate at which bytes are transferred to the disk during write operations",
|
266
|
+
"labels" => {"volume" => volume.name},
|
267
|
+
"value" => volume.counters["Disk Write Bytes/sec"].value
|
268
|
+
},
|
269
|
+
{
|
270
|
+
"type" => "counter",
|
271
|
+
"name" => "windows_logical_disk_writes_total",
|
272
|
+
"desc" => "Rate of write operations on the disk",
|
273
|
+
"labels" => {"volume" => volume.name},
|
274
|
+
"value" => volume.counters["Disk Writes/sec"].value
|
275
|
+
},
|
276
|
+
{
|
277
|
+
"type" => "counter",
|
278
|
+
"name" => "windows_logical_disk_read_seconds_total",
|
279
|
+
"desc" => "Seconds the disk was busy servicing read requests",
|
280
|
+
"labels" => {"volume" => volume.name},
|
281
|
+
"value" => volume.counters["% Disk Read Time"].value
|
282
|
+
},
|
283
|
+
{
|
284
|
+
"type" => "counter",
|
285
|
+
"name" => "windows_logical_disk_write_seconds_total",
|
286
|
+
"desc" => "Seconds the disk was busy servicing write requests",
|
287
|
+
"labels" => {"volume" => volume.name},
|
288
|
+
"value" => volume.counters["% Disk Write Time"].value
|
289
|
+
},
|
290
|
+
{
|
291
|
+
"type" => "gauge",
|
292
|
+
"name" => "windows_logical_disk_free_bytes",
|
293
|
+
"desc" => "Unused space of the disk in bytes (not real time, updates every 10-15 min)",
|
294
|
+
"labels" => {"volume" => volume.name},
|
295
|
+
"value" => volume.counters["Free Megabytes"].value * 1024 * 1024
|
296
|
+
},
|
297
|
+
{
|
298
|
+
"type" => "gauge",
|
299
|
+
"name" => "windows_logical_disk_size_bytes",
|
300
|
+
"desc" => "Total size of the disk in bytes (not real time, updates every 10-15 min)",
|
301
|
+
"labels" => {"volume" => volume.name},
|
302
|
+
"value" => volume.counters["% Free Space"].base_value * 1024 * 1024
|
303
|
+
},
|
304
|
+
{
|
305
|
+
"type" => "counter",
|
306
|
+
"name" => "windows_logical_disk_idle_seconds_total",
|
307
|
+
"desc" => "Seconds the disk was idle (not servicing read/write requests)",
|
308
|
+
"labels" => {"volume" => volume.name},
|
309
|
+
"value" => volume.counters["% Idle Time"].value
|
310
|
+
},
|
311
|
+
{
|
312
|
+
"type" => "counter",
|
313
|
+
"name" => "windows_logical_disk_split_ios_total",
|
314
|
+
"desc" => "Number of I/Os to the disk split into multiple I/Os",
|
315
|
+
"labels" => {"volume" => volume.name},
|
316
|
+
"value" => volume.counters["Split IO/Sec"].value
|
317
|
+
},
|
318
|
+
{
|
319
|
+
"type" => "counter",
|
320
|
+
"name" => "windows_logical_disk_read_latency_seconds_total",
|
321
|
+
"desc" => "Shows the average time, in seconds, of a read operation from the disk",
|
322
|
+
"labels" => {"volume" => volume.name},
|
323
|
+
"value" => volume.counters["Avg. Disk sec/Read"].value * TICKS_TO_SECONDS_SCALE_FACTOR
|
324
|
+
},
|
325
|
+
{
|
326
|
+
"type" => "counter",
|
327
|
+
"name" => "windows_logical_disk_write_latency_seconds_total",
|
328
|
+
"desc" => "Shows the average time, in seconds, of a write operation to the disk",
|
329
|
+
"labels" => {"volume" => volume.name},
|
330
|
+
"value" => volume.counters["Avg. Disk sec/Write"].value * TICKS_TO_SECONDS_SCALE_FACTOR
|
331
|
+
},
|
332
|
+
{
|
333
|
+
"type" => "counter",
|
334
|
+
"name" => "windows_logical_disk_read_write_latency_seconds_total",
|
335
|
+
"desc" => "Shows the time, in seconds, of the average disk transfer",
|
336
|
+
"labels" => {"volume" => volume.name},
|
337
|
+
"value" => volume.counters["Avg. Disk sec/Transfer"].value * TICKS_TO_SECONDS_SCALE_FACTOR
|
338
|
+
}
|
339
|
+
]
|
340
|
+
end
|
341
|
+
return records
|
342
|
+
end
|
343
|
+
|
344
|
+
def collect_memory
|
345
|
+
hpd = @cache_manager.hkey_perf_data_cache
|
346
|
+
counterset_name = "Memory"
|
347
|
+
unless hpd.key?(counterset_name)
|
348
|
+
$log.warn("Could not get HKeyPerfData CounterSet: #{counterset_name}")
|
349
|
+
return []
|
350
|
+
end
|
351
|
+
|
352
|
+
return [
|
353
|
+
{
|
354
|
+
"type" => "gauge",
|
355
|
+
"name" => "windows_memory_available_bytes",
|
356
|
+
"desc" => "The amount of physical memory immediately available for allocation to a process or for system use. It is equal to the sum of memory assigned to the standby (cached), free and zero page lists",
|
357
|
+
"labels" => {},
|
358
|
+
"value" => hpd["Memory"].instances[0].counters["Available Bytes"].value
|
359
|
+
},
|
360
|
+
{
|
361
|
+
"type" => "gauge",
|
362
|
+
"name" => "windows_memory_cache_bytes",
|
363
|
+
"desc" => "Number of bytes currently being used by the file system cache",
|
364
|
+
"labels" => {},
|
365
|
+
"value" => hpd["Memory"].instances[0].counters["Cache Bytes"].value
|
366
|
+
},
|
367
|
+
{
|
368
|
+
"type" => "gauge",
|
369
|
+
"name" => "windows_memory_cache_bytes_peak",
|
370
|
+
"desc" => "Maximum number of CacheBytes after the system was last restarted",
|
371
|
+
"labels" => {},
|
372
|
+
"value" => hpd["Memory"].instances[0].counters["Cache Bytes Peak"].value
|
373
|
+
},
|
374
|
+
{
|
375
|
+
"type" => "gauge",
|
376
|
+
"name" => "windows_memory_cache_faults_total",
|
377
|
+
"desc" => "Number of faults which occur when a page sought in the file system cache is not found there and must be retrieved from elsewhere in memory (soft fault) or from disk (hard fault)",
|
378
|
+
"labels" => {},
|
379
|
+
"value" => hpd["Memory"].instances[0].counters["Cache Faults/sec"].value
|
380
|
+
},
|
381
|
+
{
|
382
|
+
"type" => "gauge",
|
383
|
+
"name" => "windows_memory_commit_limit",
|
384
|
+
"desc" => "Amount of virtual memory, in bytes, that can be committed without having to extend the paging file(s)",
|
385
|
+
"labels" => {},
|
386
|
+
"value" => hpd["Memory"].instances[0].counters["Commit Limit"].value
|
387
|
+
},
|
388
|
+
{
|
389
|
+
"type" => "gauge",
|
390
|
+
"name" => "windows_memory_committed_bytes",
|
391
|
+
"desc" => "Amount of committed virtual memory, in bytes",
|
392
|
+
"labels" => {},
|
393
|
+
"value" => hpd["Memory"].instances[0].counters["Committed Bytes"].value
|
394
|
+
},
|
395
|
+
{
|
396
|
+
"type" => "gauge",
|
397
|
+
"name" => "windows_memory_demand_zero_faults_total",
|
398
|
+
"desc" => "The number of zeroed pages required to satisfy faults. Zeroed pages, pages emptied of previously stored data and filled with zeros, are a security feature of Windows that prevent processes from seeing data stored by earlier processes that used the memory space",
|
399
|
+
"labels" => {},
|
400
|
+
"value" => hpd["Memory"].instances[0].counters["Demand Zero Faults/sec"].value
|
401
|
+
},
|
402
|
+
{
|
403
|
+
"type" => "gauge",
|
404
|
+
"name" => "windows_memory_free_and_zero_page_list_bytes",
|
405
|
+
"desc" => "(FreeAndZeroPageListBytes)",
|
406
|
+
"labels" => {},
|
407
|
+
"value" => hpd["Memory"].instances[0].counters["Free & Zero Page List Bytes"].value
|
408
|
+
},
|
409
|
+
{
|
410
|
+
"type" => "gauge",
|
411
|
+
"name" => "windows_memory_free_system_page_table_entries",
|
412
|
+
"desc" => "Number of page table entries not being used by the system",
|
413
|
+
"labels" => {},
|
414
|
+
"value" => hpd["Memory"].instances[0].counters["Free System Page Table Entries"].value
|
415
|
+
},
|
416
|
+
{
|
417
|
+
"type" => "gauge",
|
418
|
+
"name" => "windows_memory_modified_page_list_bytes",
|
419
|
+
"desc" => "(ModifiedPageListBytes)",
|
420
|
+
"labels" => {},
|
421
|
+
"value" => hpd["Memory"].instances[0].counters["Modified Page List Bytes"].value
|
422
|
+
},
|
423
|
+
{
|
424
|
+
"type" => "gauge",
|
425
|
+
"name" => "windows_memory_page_faults_total",
|
426
|
+
"desc" => "Overall rate at which faulted pages are handled by the processor",
|
427
|
+
"labels" => {},
|
428
|
+
"value" => hpd["Memory"].instances[0].counters["Page Faults/sec"].value
|
429
|
+
},
|
430
|
+
{
|
431
|
+
"type" => "gauge",
|
432
|
+
"name" => "windows_memory_swap_page_reads_total",
|
433
|
+
"desc" => "Number of disk page reads (a single read operation reading several pages is still only counted once)",
|
434
|
+
"labels" => {},
|
435
|
+
"value" => hpd["Memory"].instances[0].counters["Page Reads/sec"].value
|
436
|
+
},
|
437
|
+
{
|
438
|
+
"type" => "gauge",
|
439
|
+
"name" => "windows_memory_swap_pages_read_total",
|
440
|
+
"desc" => "Number of pages read across all page reads (ie counting all pages read even if they are read in a single operation)",
|
441
|
+
"labels" => {},
|
442
|
+
"value" => hpd["Memory"].instances[0].counters["Pages Input/sec"].value
|
443
|
+
},
|
444
|
+
{
|
445
|
+
"type" => "gauge",
|
446
|
+
"name" => "windows_memory_swap_pages_written_total",
|
447
|
+
"desc" => "Number of pages written across all page writes (ie counting all pages written even if they are written in a single operation)",
|
448
|
+
"labels" => {},
|
449
|
+
"value" => hpd["Memory"].instances[0].counters["Pages Output/sec"].value
|
450
|
+
},
|
451
|
+
{
|
452
|
+
"type" => "gauge",
|
453
|
+
"name" => "windows_memory_swap_page_operations_total",
|
454
|
+
"desc" => "Total number of swap page read and writes (PagesPersec)",
|
455
|
+
"labels" => {},
|
456
|
+
"value" => hpd["Memory"].instances[0].counters["Pages/sec"].value
|
457
|
+
},
|
458
|
+
{
|
459
|
+
"type" => "gauge",
|
460
|
+
"name" => "windows_memory_swap_page_writes_total",
|
461
|
+
"desc" => "Number of disk page writes (a single write operation writing several pages is still only counted once)",
|
462
|
+
"labels" => {},
|
463
|
+
"value" => hpd["Memory"].instances[0].counters["Page Writes/sec"].value
|
464
|
+
},
|
465
|
+
{
|
466
|
+
"type" => "gauge",
|
467
|
+
"name" => "windows_memory_pool_nonpaged_allocs_total",
|
468
|
+
"desc" => "The number of calls to allocate space in the nonpaged pool. The nonpaged pool is an area of system memory area for objects that cannot be written to disk, and must remain in physical memory as long as they are allocated",
|
469
|
+
"labels" => {},
|
470
|
+
"value" => hpd["Memory"].instances[0].counters["Pool Nonpaged Allocs"].value
|
471
|
+
},
|
472
|
+
{
|
473
|
+
"type" => "gauge",
|
474
|
+
"name" => "windows_memory_pool_nonpaged_bytes_total",
|
475
|
+
"desc" => "Number of bytes in the non-paged pool",
|
476
|
+
"labels" => {},
|
477
|
+
"value" => hpd["Memory"].instances[0].counters["Pool Nonpaged Bytes"].value
|
478
|
+
},
|
479
|
+
{
|
480
|
+
"type" => "gauge",
|
481
|
+
"name" => "windows_memory_pool_paged_allocs_total",
|
482
|
+
"desc" => "Number of calls to allocate space in the paged pool, regardless of the amount of space allocated in each call",
|
483
|
+
"labels" => {},
|
484
|
+
"value" => hpd["Memory"].instances[0].counters["Pool Paged Allocs"].value
|
485
|
+
},
|
486
|
+
{
|
487
|
+
"type" => "gauge",
|
488
|
+
"name" => "windows_memory_pool_paged_bytes",
|
489
|
+
"desc" => "Number of bytes in the paged pool",
|
490
|
+
"labels" => {},
|
491
|
+
"value" => hpd["Memory"].instances[0].counters["Pool Paged Bytes"].value
|
492
|
+
},
|
493
|
+
{
|
494
|
+
"type" => "gauge",
|
495
|
+
"name" => "windows_memory_pool_paged_resident_bytes",
|
496
|
+
"desc" => "(PoolPagedResidentBytes)",
|
497
|
+
"labels" => {},
|
498
|
+
"value" => hpd["Memory"].instances[0].counters["Pool Paged Resident Bytes"].value
|
499
|
+
},
|
500
|
+
{
|
501
|
+
"type" => "gauge",
|
502
|
+
"name" => "windows_memory_standby_cache_core_bytes",
|
503
|
+
"desc" => "(StandbyCacheCoreBytes)",
|
504
|
+
"labels" => {},
|
505
|
+
"value" => hpd["Memory"].instances[0].counters["Standby Cache Core Bytes"].value
|
506
|
+
},
|
507
|
+
{
|
508
|
+
"type" => "gauge",
|
509
|
+
"name" => "windows_memory_standby_cache_normal_priority_bytes",
|
510
|
+
"desc" => "(StandbyCacheNormalPriorityBytes)",
|
511
|
+
"labels" => {},
|
512
|
+
"value" => hpd["Memory"].instances[0].counters["Standby Cache Normal Priority Bytes"].value
|
513
|
+
},
|
514
|
+
{
|
515
|
+
"type" => "gauge",
|
516
|
+
"name" => "windows_memory_standby_cache_reserve_bytes",
|
517
|
+
"desc" => "(StandbyCacheReserveBytes)",
|
518
|
+
"labels" => {},
|
519
|
+
"value" => hpd["Memory"].instances[0].counters["Standby Cache Reserve Bytes"].value
|
520
|
+
},
|
521
|
+
{
|
522
|
+
"type" => "gauge",
|
523
|
+
"name" => "windows_memory_system_cache_resident_bytes",
|
524
|
+
"desc" => "(SystemCacheResidentBytes)",
|
525
|
+
"labels" => {},
|
526
|
+
"value" => hpd["Memory"].instances[0].counters["System Cache Resident Bytes"].value
|
527
|
+
},
|
528
|
+
{
|
529
|
+
"type" => "gauge",
|
530
|
+
"name" => "windows_memory_system_code_resident_bytes",
|
531
|
+
"desc" => "(SystemCodeResidentBytes)",
|
532
|
+
"labels" => {},
|
533
|
+
"value" => hpd["Memory"].instances[0].counters["System Code Resident Bytes"].value
|
534
|
+
},
|
535
|
+
{
|
536
|
+
"type" => "gauge",
|
537
|
+
"name" => "windows_memory_system_code_total_bytes",
|
538
|
+
"desc" => "(SystemCodeTotalBytes)",
|
539
|
+
"labels" => {},
|
540
|
+
"value" => hpd["Memory"].instances[0].counters["System Code Total Bytes"].value
|
541
|
+
},
|
542
|
+
{
|
543
|
+
"type" => "gauge",
|
544
|
+
"name" => "windows_memory_system_driver_resident_bytes",
|
545
|
+
"desc" => "(SystemDriverResidentBytes)",
|
546
|
+
"labels" => {},
|
547
|
+
"value" => hpd["Memory"].instances[0].counters["System Driver Resident Bytes"].value
|
548
|
+
},
|
549
|
+
{
|
550
|
+
"type" => "gauge",
|
551
|
+
"name" => "windows_memory_system_driver_total_bytes",
|
552
|
+
"desc" => "(SystemDriverTotalBytes)",
|
553
|
+
"labels" => {},
|
554
|
+
"value" => hpd["Memory"].instances[0].counters["System Driver Total Bytes"].value
|
555
|
+
},
|
556
|
+
{
|
557
|
+
"type" => "gauge",
|
558
|
+
"name" => "windows_memory_transition_faults_total",
|
559
|
+
"desc" => "(TransitionFaultsPersec)",
|
560
|
+
"labels" => {},
|
561
|
+
"value" => hpd["Memory"].instances[0].counters["Transition Faults/sec"].value
|
562
|
+
},
|
563
|
+
{
|
564
|
+
"type" => "gauge",
|
565
|
+
"name" => "windows_memory_transition_pages_repurposed_total",
|
566
|
+
"desc" => "(TransitionPagesRePurposedPersec)",
|
567
|
+
"labels" => {},
|
568
|
+
"value" => hpd["Memory"].instances[0].counters["Transition Pages RePurposed/sec"].value
|
569
|
+
},
|
570
|
+
{
|
571
|
+
"type" => "gauge",
|
572
|
+
"name" => "windows_memory_write_copies_total",
|
573
|
+
"desc" => "The number of page faults caused by attempting to write that were satisfied by copying the page from elsewhere in physical memory",
|
574
|
+
"labels" => {},
|
575
|
+
"value" => hpd["Memory"].instances[0].counters["Write Copies/sec"].value
|
576
|
+
}
|
577
|
+
]
|
578
|
+
end
|
579
|
+
|
580
|
+
def collect_net
|
581
|
+
hpd = @cache_manager.hkey_perf_data_cache
|
582
|
+
counterset_name = "Network Interface"
|
583
|
+
unless hpd.key?(counterset_name)
|
584
|
+
$log.warn("Could not get HKeyPerfData CounterSet: #{counterset_name}")
|
585
|
+
return []
|
586
|
+
end
|
587
|
+
|
588
|
+
records = []
|
589
|
+
for nic in hpd[counterset_name].instances do
|
590
|
+
name = nic.name.gsub!(/[^a-zA-Z0-9]/, '_')
|
591
|
+
if name == ""
|
592
|
+
next
|
593
|
+
end
|
594
|
+
|
595
|
+
records += [
|
596
|
+
{
|
597
|
+
"type" => "counter",
|
598
|
+
"name" => "windows_net_bytes_received_total",
|
599
|
+
"desc" => "Total bytes received by interface",
|
600
|
+
"labels" => {"nic": name},
|
601
|
+
"value" => nic.counters["Bytes Received/sec"].value
|
602
|
+
},
|
603
|
+
{
|
604
|
+
"type" => "counter",
|
605
|
+
"name" => "windows_net_bytes_sent_total",
|
606
|
+
"desc" => "Total bytes transmitted by interface",
|
607
|
+
"labels" => {"nic": name},
|
608
|
+
"value" => nic.counters["Bytes Sent/sec"].value
|
609
|
+
},
|
610
|
+
{
|
611
|
+
"type" => "counter",
|
612
|
+
"name" => "windows_net_bytes_total",
|
613
|
+
"desc" => "Total bytes received and transmitted by interface",
|
614
|
+
"labels" => {"nic": name},
|
615
|
+
"value" => nic.counters["Bytes Total/sec"].value
|
616
|
+
},
|
617
|
+
{
|
618
|
+
"type" => "counter",
|
619
|
+
"name" => "windows_net_packets_outbound_discarded_total",
|
620
|
+
"desc" => "Total outbound packets that were chosen to be discarded even though no errors had been detected to prevent transmission",
|
621
|
+
"labels" => {"nic": name},
|
622
|
+
"value" => nic.counters["Packets Outbound Discarded"].value
|
623
|
+
},
|
624
|
+
{
|
625
|
+
"type" => "counter",
|
626
|
+
"name" => "windows_net_packets_outbound_errors_total",
|
627
|
+
"desc" => "Total packets that could not be transmitted due to errors",
|
628
|
+
"labels" => {"nic": name},
|
629
|
+
"value" => nic.counters["Packets Outbound Errors"].value
|
630
|
+
},
|
631
|
+
{
|
632
|
+
"type" => "counter",
|
633
|
+
"name" => "windows_net_packets_total",
|
634
|
+
"desc" => "Total packets received and transmitted by interface",
|
635
|
+
"labels" => {"nic": name},
|
636
|
+
"value" => nic.counters["Packets/sec"].value
|
637
|
+
},
|
638
|
+
{
|
639
|
+
"type" => "counter",
|
640
|
+
"name" => "windows_net_packets_received_discarded_total",
|
641
|
+
"desc" => "Total inbound packets that were chosen to be discarded even though no errors had been detected to prevent delivery",
|
642
|
+
"labels" => {"nic": name},
|
643
|
+
"value" => nic.counters["Packets Received Discarded"].value
|
644
|
+
},
|
645
|
+
{
|
646
|
+
"type" => "counter",
|
647
|
+
"name" => "windows_net_packets_received_errors_total",
|
648
|
+
"desc" => "Total packets that could not be received due to errors",
|
649
|
+
"labels" => {"nic": name},
|
650
|
+
"value" => nic.counters["Packets Received Errors"].value
|
651
|
+
},
|
652
|
+
{
|
653
|
+
"type" => "counter",
|
654
|
+
"name" => "windows_net_packets_received_total",
|
655
|
+
"desc" => "Total packets received by interface",
|
656
|
+
"labels" => {"nic": name},
|
657
|
+
"value" => nic.counters["Packets Received/sec"].value
|
658
|
+
},
|
659
|
+
{
|
660
|
+
"type" => "counter",
|
661
|
+
"name" => "windows_net_packets_received_unknown_total",
|
662
|
+
"desc" => "Total packets received by interface that were discarded because of an unknown or unsupported protocol",
|
663
|
+
"labels" => {"nic": name},
|
664
|
+
"value" => nic.counters["Packets Received Unknown"].value
|
665
|
+
},
|
666
|
+
{
|
667
|
+
"type" => "counter",
|
668
|
+
"name" => "windows_net_packets_sent_total",
|
669
|
+
"desc" => "Total packets transmitted by interface",
|
670
|
+
"labels" => {"nic": name},
|
671
|
+
"value" => nic.counters["Packets Sent/sec"].value
|
672
|
+
},
|
673
|
+
{
|
674
|
+
"type" => "gauge",
|
675
|
+
"name" => "windows_net_current_bandwidth_bytes",
|
676
|
+
"desc" => "Estimate of the interface's current bandwidth in bytes per second",
|
677
|
+
"labels" => {"nic": name},
|
678
|
+
"value" => nic.counters["Current Bandwidth"].value / 8
|
679
|
+
}
|
680
|
+
]
|
681
|
+
end
|
682
|
+
return records
|
683
|
+
end
|
684
|
+
|
685
|
+
def collect_os
|
686
|
+
hpd = @cache_manager.hkey_perf_data_cache
|
687
|
+
mem = @cache_manager.memory_status_cache
|
688
|
+
work = @cache_manager.work_station_info_cache
|
689
|
+
perf = @cache_manager.performance_info_cache
|
690
|
+
reg = @cache_manager.registry_info_cache
|
691
|
+
|
692
|
+
records = [
|
693
|
+
{
|
694
|
+
"type" => "gauge",
|
695
|
+
"name" => "windows_os_info",
|
696
|
+
"desc" => "Contains full product name & version in labels",
|
697
|
+
"labels" => {
|
698
|
+
:product => "Microsoft #{reg[:ProductName]}",
|
699
|
+
:version => "#{work[:VersionMajor]}.#{work[:VersionMinor]}.#{reg[:CurrentBuildNumber]}"
|
700
|
+
},
|
701
|
+
"value" => 1.0
|
702
|
+
},
|
703
|
+
{
|
704
|
+
"type" => "gauge",
|
705
|
+
"name" => "windows_os_physical_memory_free_bytes",
|
706
|
+
"desc" => "Bytes of physical memory currently unused and available",
|
707
|
+
"labels" => {},
|
708
|
+
"value" => mem[:AvailPhys]
|
709
|
+
},
|
710
|
+
{
|
711
|
+
"type" => "gauge",
|
712
|
+
"name" => "windows_os_time",
|
713
|
+
"desc" => "Current time as reported by the operating system, in Unix time",
|
714
|
+
"labels" => {},
|
715
|
+
"value" => Fluent::EventTime.now.to_f
|
716
|
+
},
|
717
|
+
{
|
718
|
+
"type" => "gauge",
|
719
|
+
"name" => "windows_os_timezone",
|
720
|
+
"desc" => "Current timezone as reported by the operating system",
|
721
|
+
"labels" => {:timezone => Time.now.strftime("%z")},
|
722
|
+
"value" => 1.0
|
723
|
+
},
|
724
|
+
{
|
725
|
+
"type" => "gauge",
|
726
|
+
"name" => "windows_os_virtual_memory_free_bytes",
|
727
|
+
"desc" => "Bytes of virtual memory currently unused and available",
|
728
|
+
"labels" => {},
|
729
|
+
"value" => mem[:AvailPageFile]
|
730
|
+
},
|
731
|
+
{
|
732
|
+
"type" => "gauge",
|
733
|
+
"name" => "windows_os_processes_limit",
|
734
|
+
"desc" => "Maximum number of process contexts the operating system can support. The default value set by the provider is 4294967295 (0xFFFFFFFF)",
|
735
|
+
"labels" => {},
|
736
|
+
# prometheus-community/windows-exporter/collector/os.go#L275
|
737
|
+
"value" => 4294967295.0
|
738
|
+
},
|
739
|
+
{
|
740
|
+
"type" => "gauge",
|
741
|
+
"name" => "windows_os_process_memory_limit_bytes",
|
742
|
+
"desc" => "Maximum number of bytes of memory that can be allocated to a process",
|
743
|
+
"labels" => {},
|
744
|
+
"value" => mem[:TotalVirtual]
|
745
|
+
},
|
746
|
+
{
|
747
|
+
"type" => "gauge",
|
748
|
+
"name" => "windows_os_processes",
|
749
|
+
"desc" => "Number of process contexts currently loaded or running on the operating system",
|
750
|
+
"labels" => {},
|
751
|
+
"value" => perf[:ProcessCount]
|
752
|
+
},
|
753
|
+
{
|
754
|
+
"type" => "gauge",
|
755
|
+
"name" => "windows_os_users",
|
756
|
+
"desc" => "Number of user sessions for which the operating system is storing state information currently. For a list of current active logon sessions.",
|
757
|
+
"labels" => {},
|
758
|
+
"value" => work[:LoggedOnUsers]
|
759
|
+
},
|
760
|
+
{
|
761
|
+
"type" => "gauge",
|
762
|
+
"name" => "windows_os_paging_limit_bytes",
|
763
|
+
"desc" => "Total number of bytes that can be sotred in the operating system paging files. 0 (zero) indicates that there are no paging files",
|
764
|
+
"labels" => {},
|
765
|
+
"value" => reg[:PagingLimitBytes]
|
766
|
+
},
|
767
|
+
{
|
768
|
+
"type" => "gauge",
|
769
|
+
"name" => "windows_os_virtual_memory_bytes",
|
770
|
+
"desc" => "Bytes of virtual memory",
|
771
|
+
"labels" => {},
|
772
|
+
"value" => mem[:TotalPageFile],
|
773
|
+
},
|
774
|
+
{
|
775
|
+
"type" => "gauge",
|
776
|
+
"name" => "windows_os_visible_memory_bytes",
|
777
|
+
"desc" => "Total bytes of physical memory available to the operating system. This value does not necessarily indicate the true amount of physical memory, but what is reported to the operating system as available to it",
|
778
|
+
"labels" => {},
|
779
|
+
"value" => mem[:TotalPhys]
|
780
|
+
}
|
781
|
+
]
|
782
|
+
|
783
|
+
counterset_name = "Paging File"
|
784
|
+
unless hpd.key?(counterset_name)
|
785
|
+
$log.warn("Could not get HKeyPerfData CounterSet: #{counterset_name}")
|
786
|
+
return records
|
787
|
+
end
|
788
|
+
|
789
|
+
pfusage = 0
|
790
|
+
for ins in hpd[counterset_name].instances do
|
791
|
+
unless ins.name.downcase.include?("_total")
|
792
|
+
pfusage += ins.counters["% Usage"].value
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
796
|
+
records += [
|
797
|
+
{
|
798
|
+
"type" => "gauge",
|
799
|
+
"name" => "windows_os_paging_free_bytes",
|
800
|
+
"desc" => "Number of bytes that can be mapped into the operating system paging files without causing any other pages to be swapped out",
|
801
|
+
"labels" => {},
|
802
|
+
"value" => reg[:PagingLimitBytes] - pfusage * perf[:PageSize]
|
803
|
+
}
|
804
|
+
]
|
805
|
+
|
806
|
+
return records
|
807
|
+
end
|
808
|
+
end
|
809
|
+
|
810
|
+
module HKeyPerfDataWhiteList
|
811
|
+
NAMES = [
|
812
|
+
"Processor Information",
|
813
|
+
"LogicalDisk",
|
814
|
+
"Memory",
|
815
|
+
"Network Interface",
|
816
|
+
"Paging File",
|
817
|
+
]
|
818
|
+
end
|
819
|
+
|
820
|
+
class CacheManager
|
821
|
+
include Constants
|
822
|
+
|
823
|
+
attr_reader :hkey_perf_data_cache
|
824
|
+
attr_reader :memory_status_cache
|
825
|
+
attr_reader :work_station_info_cache
|
826
|
+
attr_reader :performance_info_cache
|
827
|
+
attr_reader :registry_info_cache
|
828
|
+
|
829
|
+
def initialize
|
830
|
+
@hkey_perf_data_reader = HKeyPerfDataReader::Reader.new(
|
831
|
+
object_name_whitelist: HKeyPerfDataWhiteList::NAMES,
|
832
|
+
logger: $log
|
833
|
+
)
|
834
|
+
|
835
|
+
@hkey_perf_data_cache = nil
|
836
|
+
@memory_status_cache = nil
|
837
|
+
@work_station_info_cache = nil
|
838
|
+
@performance_info_cache = nil
|
839
|
+
@registry_info_cache = nil
|
840
|
+
end
|
841
|
+
|
842
|
+
def update
|
843
|
+
@hkey_perf_data_cache = get_hkey_perf_data()
|
844
|
+
@memory_status_cache = WinFFI.GetMemoryStatus()
|
845
|
+
@work_station_info_cache = WinFFI.GetWorkstationInfo()
|
846
|
+
@performance_info_cache = WinFFI.GetPerformanceInfo()
|
847
|
+
@registry_info_cache = WinFFI.GetRegistryInfo()
|
848
|
+
end
|
849
|
+
|
850
|
+
private
|
851
|
+
|
852
|
+
def get_hkey_perf_data
|
853
|
+
data = @hkey_perf_data_reader.read
|
854
|
+
|
855
|
+
data.each do |object_name, object|
|
856
|
+
object.instances.each do |instance|
|
857
|
+
instance.counters.each do |counter_name, counter|
|
858
|
+
counter.value = calc_hpd_counter_value(
|
859
|
+
object, counter.type, counter.value
|
860
|
+
)
|
861
|
+
end
|
862
|
+
end
|
863
|
+
end
|
864
|
+
|
865
|
+
data
|
866
|
+
end
|
867
|
+
|
868
|
+
def calc_hpd_counter_value(object, type, value)
|
869
|
+
# https://github.com/prometheus-community/windows_exporter/blob/master/collector/perflib.go
|
870
|
+
|
871
|
+
case type
|
872
|
+
when PERF_ELAPSED_TIME
|
873
|
+
return (value - WINDOWS_EPOCH) / object.perf_freq
|
874
|
+
when PERF_100NSEC_TIMER, PERF_PRECISION_100NS_TIMER
|
875
|
+
return value * TICKS_TO_SECONDS_SCALE_FACTOR
|
876
|
+
else
|
877
|
+
return value
|
878
|
+
end
|
879
|
+
end
|
880
|
+
end
|
881
|
+
end
|
882
|
+
end
|