2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
10 # | Copyright Mathias Kettner 2018 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 # .--Parse---------------------------------------------------------------.
29 # | | _ \ __ _ _ __ ___ ___ |
30 # | | |_) / _` | '__/ __|/ _ \ |
31 # | | __/ (_| | | \__ \ __/ |
32 # | |_| \__,_|_| |___/\___| |
34 # '----------------------------------------------------------------------'
37 def jolokia_basic_split(line
, expected_length
):
38 # line should consist of $expected_length tokens,
39 # if there are more, we assume the second one
40 # was split up by it's spaces.
41 if len(line
) == expected_length
:
43 if len(line
) < expected_length
:
44 raise ValueError("Too few values: %r (expected >= %d)" \
45 % (line
, expected_length
))
46 if expected_length
< 2:
47 raise NotImplementedError("use 'join' to create single token")
49 while len(tokens
) > expected_length
:
50 # len(tokens) is at least 3!
51 tokens
[1] += " %s" % tokens
.pop(2)
55 def jolokoia_extract_opt(instance_raw
):
56 if ',' not in instance_raw
:
57 return instance_raw
, {}, []
59 instance
, raw
= instance_raw
.split(',', 1)
63 for part
in raw
.split(','):
65 part
= part
.split(":", 1)[1]
67 key
, val
= part
.split("=")
72 return instance
, attr
, pos
75 # .--Parse function------------------------------------------------------.
77 # | | _ \ __ _ _ __ ___ ___ / _|_ _ _ __ ___| |_(_) ___ _ __ |
78 # | | |_) / _` | '__/ __|/ _ \ | |_| | | | '_ \ / __| __| |/ _ \| '_ \ |
79 # | | __/ (_| | | \__ \ __/ | _| |_| | | | | (__| |_| | (_) | | | | |
80 # | |_| \__,_|_| |___/\___| |_| \__,_|_| |_|\___|\__|_|\___/|_| |_| |
82 # '----------------------------------------------------------------------'
85 def jolokia_metrics_parse(info
):
88 if len(line
) > 1 and line
[1] == "ERROR":
92 inst_raw
, var
, value
= jolokia_basic_split(line
, 3)
96 inst
, attributes
, positional
= jolokoia_extract_opt(inst_raw
)
98 parsed
.setdefault(inst
, {})
100 if 'type' in attributes
:
101 bean_name
= attributes
.pop('name')
102 bean_type
= attributes
.pop('type')
103 # backwards compatibility
104 bean_type
= {"GarbageCollector": "gc", "ThreadPool": "tp"}.get(bean_type
, bean_type
)
105 # maybe do this for all types?
106 if bean_type
== "tp":
107 bean_name
= bean_name
.replace('"', '')
109 bean
= parsed
[inst
].setdefault(bean_type
, {}).setdefault(bean_name
, {})
111 bean
.update(attributes
)
115 app_dict
= parsed
[inst
].setdefault('apps', {}).setdefault(app
, {})
116 if len(positional
) > 1:
117 servlet
= positional
[1]
118 app_dict
.setdefault('servlets', {}).setdefault(servlet
, {})
119 app_dict
['servlets'][servlet
][var
] = value
121 app_dict
[var
] = value
123 parsed
[inst
][var
] = value
128 # .--Generic inventory functions-----------------------------------------.
130 # | / ___| ___ _ __ ___ _ __(_) ___ |
131 # | | | _ / _ \ '_ \ / _ \ '__| |/ __| |
132 # | | |_| | __/ | | | __/ | | | (__ |
133 # | \____|\___|_| |_|\___|_| |_|\___| |
136 # | (_)_ ____ _____ _ __ | |_ ___ _ __ _ _ |
137 # | | | '_ \ \ / / _ \ '_ \| __/ _ \| '__| | | | |
138 # | | | | | \ V / __/ | | | || (_) | | | |_| | |
139 # | |_|_| |_|\_/ \___|_| |_|\__\___/|_| \__, | |
142 # | / _|_ _ _ __ ___| |_(_) ___ _ __ ___ |
143 # | | |_| | | | '_ \ / __| __| |/ _ \| '_ \/ __| |
144 # | | _| |_| | | | | (__| |_| | (_) | | | \__ \ |
145 # | |_| \__,_|_| |_|\___|\__|_|\___/|_| |_|___/ |
147 # '----------------------------------------------------------------------'
150 def inventory_jolokia_metrics(info
, what
):
151 parsed
= jolokia_metrics_parse(info
)
157 elif what
== 'threads':
158 levels
= 'jolokia_metrics_threads_default_levels'
160 for instance
, data
in parsed
.items():
162 continue # No connection to agent currently
164 if what
== 'uptime' and "Uptime" not in data
:
166 if what
== 'mem' and ("HeapMemoryUsage" not in data
or "NonHeapMemoryUsage" not in data
or
167 "HeapMemoryMax" not in data
or "NonHeapMemoryMax" not in data
):
168 # don't add memory check if we don't have the necessary data
170 yield instance
, levels
173 def inventory_jolokia_metrics_apps(info
, what
):
175 parsed
= jolokia_metrics_parse(info
)
177 if what
== 'app_sess':
178 levels
= 'jolokia_metrics_app_sess_default_levels'
179 needed_key
= ["Sessions", "activeSessions"]
180 elif what
== 'bea_app_sess':
181 levels
= 'jolokia_metrics_app_sess_default_levels'
182 needed_key
= ["OpenSessionsCurrentCount"]
183 elif what
== 'queue':
184 needed_key
= ["QueueLength"]
185 levels
= "jolokia_metrics_queue_default_levels"
187 elif what
== 'bea_requests':
188 needed_key
= ["CompletedRequestCount"]
190 elif what
== 'requests':
191 needed_key
= ["requestCount"]
193 elif what
== 'threads':
194 needed_key
= ["StandbyThreadCount"]
197 needed_key
= ["Running", "stateName"]
200 # this handles information from BEA, they stack one level
201 # higher than the rest.
202 if what
== 'bea_app_sess':
203 for inst
, vals
in parsed
.iteritems():
205 continue # no data from agent
207 for app
, appstate
in vals
.get('apps', {}).items():
208 if 'servlets' in appstate
:
209 for nk
in needed_key
:
210 for servlet
in appstate
['servlets']:
211 if nk
in appstate
['servlets'][servlet
]:
212 inv
.append(('%s %s %s' % (inst
, app
, servlet
), levels
))
214 # This does the same for tomcat
215 for inst
, vals
in parsed
.iteritems():
217 continue # no data from agent
219 for app
, appstate
in vals
.get('apps', {}).items():
220 for nk
in needed_key
:
222 inv
.append(('%s %s' % (inst
, app
), levels
))