2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
10 # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 # Example output from agent
28 # <<<winperf_phydisk>>>
30 # 2 instances: 0_C: _Total
32 # -34 235822560 235822560 type(20570500)
33 # -34 2664021277 2664021277 type(40030500)
34 # 1166 235822560 235822560 type(550500) ----> Average Disk Queue Length
35 # -32 109877176 109877176 type(20570500)
36 # -32 2664021277 2664021277 type(40030500)
37 # 1168 109877176 109877176 type(550500) ----> Average Disk Read Queue Length
38 # -30 125945384 125945384 type(20570500)
39 # -30 2664021277 2664021277 type(40030500)
40 # 1170 125945384 125945384 type(550500) ----> Average Disk Write Queue Length
41 # -28 3526915777 3526915777 average_timer
42 # -28 36283 36283 average_base
43 # -26 1888588843 1888588843 average_timer ----> Average Disk Seconds/Read
44 # -26 17835 17835 average_base
45 # -24 1638326933 1638326933 average_timer
46 # -24 18448 18448 average_base ----> Average Disk Seconds/Write
47 # -22 36283 36283 counter
48 # -20 17835 17835 counter ----> Disk Reads/sec
49 # -18 18448 18448 counter ----> Disk Writes/sec
50 # -16 1315437056 1315437056 bulk_count
51 # -14 672711680 672711680 bulk_count ----> Disk Read Bytes/sec
52 # -12 642725376 642725376 bulk_count ----> Disk Write Bytes/sec
53 # -10 1315437056 1315437056 average_bulk
54 # -10 36283 36283 average_base
55 # -8 672711680 672711680 average_bulk
56 # -8 17835 17835 average_base
57 # -6 642725376 642725376 average_bulk
58 # -6 18448 18448 average_base
59 # 1248 769129229 769129229 type(20570500)
60 # 1248 2664021277 2664021277 type(40030500)
61 # 1250 1330 1330 counter
64 def winperf_phydisk_convert(info
):
65 # node_info has been activated. This check simply ignores this
67 # In case disk performance counters are not enabled, the agent sends
68 # an almost empty section, where the second line is missing completely
69 def disk_perfcounters_disabled(info
):
70 nodes
= set([l
[0] for l
in info
])
71 return len(nodes
) == len(info
)
73 if disk_perfcounters_disabled(info
):
79 def finalize_block(nodename
):
80 # Missing columns are donted by negative values (Linux sends here latency information)
82 [nodename
for _x
in current_disks
],
84 current_disk_read_bytes
or [],
85 current_disk_write_bytes
or [],
86 current_disk_reads
or [],
87 current_disk_writes
or [],
88 [-1 for _x
in current_disks
],
89 current_disk_readq_ctrs
or [],
90 current_disk_writeq_ctrs
or [],
91 current_disk_seconds_per_read
or [],
92 current_disk_seconds_per_read_base
or [],
93 current_disk_seconds_per_write
or [],
94 current_disk_seconds_per_write_base
or [],
101 if line
[2] == "instances:":
102 if current_node
!= "":
103 entries
.extend(finalize_block(current_node
))
104 current_node
= line
[0]
106 for disk_id
in line
[3:-1]:
107 disk_id
= disk_id
.split('_')
109 if disk_id
[-1] not in current_disks
:
110 disk_id
= disk_id
[-1]
112 disk_id
= "%s_%s" % (disk_id
[-1], disk_id
[0])
113 current_disks
.append(disk_id
)
114 elif line
[1] == '-14':
115 current_disk_read_bytes
= map(int, line
[2:-2])
116 elif line
[1] == '-12':
117 current_disk_write_bytes
= map(int, line
[2:-2])
118 elif line
[1] == '-20':
119 current_disk_reads
= map(int, line
[2:-2])
120 elif line
[1] == '-18':
121 current_disk_writes
= map(int, line
[2:-2])
122 elif line
[1] == '1168': # Average Disk Read Queue Length
123 current_disk_readq_ctrs
= map(int, line
[2:-2])
124 elif line
[1] == '1170': # Average Disk Read Queue Length
125 current_disk_writeq_ctrs
= map(int, line
[2:-2])
126 elif line
[1] == '-24':
127 if line
[-1] == 'average_base':
128 current_disk_seconds_per_write_base
= map(int, line
[2:-2])
130 current_disk_seconds_per_write
= map(int, line
[2:-2])
131 elif line
[1] == '-26':
132 if line
[-1] == 'average_base':
133 current_disk_seconds_per_read_base
= map(int, line
[2:-2])
135 current_disk_seconds_per_read
= map(int, line
[2:-2])
136 except StopIteration:
137 if current_node
!= "":
138 entries
.extend(finalize_block(current_node
))
143 def inventory_winperf_phydisk(info
):
144 return inventory_diskstat_generic(winperf_phydisk_convert(info
))
147 def check_winperf_phydisk(item
, params
, info
):
149 if len(init_line
) >= 4:
150 frequency
= int(init_line
[3])
154 this_time
= float(init_line
[1])
156 # convert input data to a dictionary. This also calculates rates, the non-dict
157 # version of check_diskstat calculates those itself. Also, this means we don't create
158 # useless counters during inventory which is neater
159 def dictify(converted_info
):
162 for disk
in converted_info
:
163 disk_id
= "%s_%s" % (disk
[0], disk
[1])
167 'read_ios': get_rate("readios_" + disk_id
, this_time
, disk
[4]),
168 'read_throughput': get_rate("readtp_" + disk_id
, this_time
, disk
[2]),
169 'write_ios': get_rate("writeios_" + disk_id
, this_time
, disk
[5]),
170 'write_throughput': get_rate("writetp_" + disk_id
, this_time
, disk
[3]),
173 # using 1 for the base if the counter didn't increase. This makes little to no sense
174 sec_per_read_counter
= get_rate("spr_counter_" + disk_id
, this_time
, disk
[9])
175 sec_per_read_base
= get_rate("spr_base_" + disk_id
, this_time
, disk
[10]) or 1
176 sec_per_write_counter
= get_rate("spw_counter_" + disk_id
, this_time
, disk
[11])
177 sec_per_write_base
= get_rate("spw_base_" + disk_id
, this_time
, disk
[12]) or 1
178 result
[disk
[1]].update({
179 'average_read_wait': (sec_per_read_counter
/ frequency
) / sec_per_read_base
,
180 'average_write_wait': (sec_per_write_counter
/ frequency
) / sec_per_write_base
,
183 # Queue Lengths (currently only Windows). Windows uses counters here.
184 # I have not understood, why....
185 for what
, ctr
in [("read_ql", disk
[7]), ("write_ql", disk
[8])]:
186 qlx
= get_rate("%s_%s" % (what
, disk_id
), this_time
, int(ctr
))
187 ql
= qlx
/ 10000000.0
188 result
[disk
[1]].update({what
: ql
})
192 return check_diskstat_dict(item
, params
, dictify(winperf_phydisk_convert(info
)))
195 check_info
["winperf_phydisk"] = {
196 'check_function': check_winperf_phydisk
,
197 'inventory_function': inventory_winperf_phydisk
,
198 'service_description': 'Disk IO %s',
200 'has_perfdata': True,
201 'includes': ["diskstat.include"],