Refactoring: Changed all check parameters starting with an 'o' to the new rulespec...
[check_mk.git] / checks / winperf_phydisk
blobaaea001bb783f971d7ee1b80359437d058ac9326
1 #!/usr/bin/python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
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>>>
29 # 1352457622.31 234
30 # 2 instances: 0_C: _Total
31 # -36 0 0 rawcount
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
66 # for now.
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):
74 return []
76 lines = iter(info)
77 entries = []
79 def finalize_block(nodename):
80 # Missing columns are donted by negative values (Linux sends here latency information)
81 return zip(
82 [nodename for _x in current_disks],
83 current_disks or [],
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 [],
97 current_node = ""
98 try:
99 while True:
100 line = lines.next()
101 if line[2] == "instances:":
102 if current_node != "":
103 entries.extend(finalize_block(current_node))
104 current_node = line[0]
105 current_disks = []
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]
111 else:
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])
129 else:
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])
134 else:
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))
140 return entries
143 def inventory_winperf_phydisk(info):
144 return inventory_diskstat_generic(winperf_phydisk_convert(info))
147 def check_winperf_phydisk(item, params, info):
148 init_line = info[0]
149 if len(init_line) >= 4:
150 frequency = int(init_line[3])
151 else:
152 frequency = None
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):
160 result = {}
162 for disk in converted_info:
163 disk_id = "%s_%s" % (disk[0], disk[1])
165 result[disk[1]] = {
166 'node': disk[0],
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]),
172 if frequency:
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})
190 return result
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',
199 'node_info': True,
200 'has_perfdata': True,
201 'includes': ["diskstat.include"],
202 'group': 'disk_io',