1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package it.jnrpe.plugin;
17
18 import it.jnrpe.ICommandLine;
19 import it.jnrpe.ReturnValue;
20 import it.jnrpe.ReturnValue.UnitOfMeasure;
21 import it.jnrpe.Status;
22 import it.jnrpe.plugin.utils.Utils;
23 import it.jnrpe.plugins.PluginBase;
24 import it.jnrpe.utils.BadThresholdException;
25 import it.jnrpe.utils.ThresholdUtil;
26
27 import java.io.IOException;
28 import java.io.StringReader;
29 import java.io.UnsupportedEncodingException;
30 import java.net.URL;
31 import java.util.Properties;
32
33 import javax.xml.parsers.DocumentBuilder;
34 import javax.xml.parsers.DocumentBuilderFactory;
35 import javax.xml.parsers.ParserConfigurationException;
36 import javax.xml.xpath.XPath;
37 import javax.xml.xpath.XPathConstants;
38 import javax.xml.xpath.XPathExpressionException;
39 import javax.xml.xpath.XPathFactory;
40
41 import org.apache.commons.codec.binary.Base64;
42 import org.w3c.dom.Document;
43 import org.w3c.dom.Element;
44 import org.w3c.dom.NodeList;
45 import org.xml.sax.InputSource;
46 import org.xml.sax.SAXException;
47
48
49
50
51
52
53
54
55 public class CheckTomcat extends PluginBase {
56
57
58
59
60 public static final String DEFAULT_PORT = "8080";
61
62
63
64
65 public static final String DEFAULT_URI = "/manager/status?XML=true";
66
67
68
69
70 public static final String DEFAULT_TIMEOUT = "10";
71
72
73
74
75
76
77
78
79
80
81 @Override
82 public final ReturnValue execute(final ICommandLine cl)
83 throws BadThresholdException {
84 log.debug("check_tomcat");
85 String username = cl.getOptionValue("username");
86 String password = cl.getOptionValue("password");
87 String hostname = cl.getOptionValue("hostname");
88
89 String port = cl.getOptionValue("port", DEFAULT_PORT);
90 String uri = cl.getOptionValue("uri", DEFAULT_URI);
91 String warning = cl.getOptionValue("warning");
92 String critical = cl.getOptionValue("critical");
93
94 int timeout = Integer.parseInt(cl.getOptionValue("timeout",
95 DEFAULT_TIMEOUT));
96
97 if (!uri.startsWith("/")) {
98 uri = "/" + uri;
99 }
100
101 String protocol;
102 String credentials;
103
104 if (cl.hasOption("ssl")) {
105 protocol = "https://";
106 } else {
107 protocol = "http://";
108 }
109
110 if (password != null) {
111 credentials = username + ":" + password;
112 } else {
113 credentials = username + ":";
114 }
115
116 String url = protocol + credentials + "@" + hostname + ":" + port + uri;
117
118 String encoded = null;
119 try {
120 encoded = Base64.encodeBase64String((username + ":" + password)
121 .getBytes("UTF-8"));
122 } catch (UnsupportedEncodingException e) {
123 throw new BadThresholdException("Error: " + e.getMessage(), e);
124 }
125 Properties props = new Properties();
126 props.put("Authorization", "Basic " + encoded);
127 String response = null;
128 String errmsg = null;
129 try {
130 response = Utils.getUrl(new URL(url), props, timeout * 1000);
131
132 } catch (Exception e) {
133 log.info("Plugin execution failed : " + e.getMessage(), e);
134 errmsg = e.getMessage();
135 }
136
137 if (response == null) {
138 return new ReturnValue(Status.WARNING, errmsg);
139 }
140
141 boolean checkThreads = cl.hasOption("threads");
142 boolean checkMemory = cl.hasOption("memory");
143
144
145 if (checkThreads && checkMemory) {
146 throw new BadThresholdException(
147 "Either --memory or --threads allowed in command.");
148 }
149 return analyseStatus(response, warning, critical, checkMemory,
150 checkThreads);
151 }
152
153
154
155
156
157
158
159
160
161
162
163
164 private ReturnValue analyseStatus(final String xml, final String warning,
165 final String critical, boolean checkMemory, boolean checkThreads)
166 throws BadThresholdException {
167 StringBuffer buff = new StringBuffer();
168 log.debug("checkThreads " + checkThreads);
169 log.debug("checkMemory " + checkMemory);
170 log.debug("critical " + critical);
171 log.debug("warning " + warning);
172
173 ReturnValue retVal = new ReturnValue(Status.OK, null);
174 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
175 DocumentBuilder builder = null;
176 try {
177 builder = factory.newDocumentBuilder();
178 } catch (ParserConfigurationException e) {
179
180 throw new IllegalStateException(e);
181 }
182 int freeMem = 0;
183 int totalMem = 0;
184 int availableMem = 0;
185 int maxMem = 0;
186 int memUse = 0;
187 int maxMemMb = 0;
188 int availableMemMb = 0;
189 int currentThreadCount = 0;
190 int currentThreadsBusy = 0;
191 int threadsAvailable = 0;
192 int maxThreads = 0;
193
194 InputSource is = new InputSource(new StringReader(xml));
195 try {
196 Document doc = builder.parse(is);
197 XPathFactory xPathfactory = XPathFactory.newInstance();
198 XPath xpath = xPathfactory.newXPath();
199 Element root = (Element) xpath.compile("//status").evaluate(
200 doc.getDocumentElement(), XPathConstants.NODE);
201 Element memory = (Element) xpath.compile("//status/jvm/memory")
202 .evaluate(doc.getDocumentElement(), XPathConstants.NODE);
203
204
205 freeMem = Integer.parseInt(memory.getAttribute("free"));
206 totalMem = Integer.parseInt(memory.getAttribute("total"));
207 maxMem = Integer.parseInt(memory.getAttribute("max"));
208 availableMem = freeMem + maxMem - totalMem;
209
210 maxMemMb = maxMem / (1024 * 1024);
211 availableMemMb = availableMem / (1024 * 1024);
212 memUse = (maxMem - availableMem);
213 buff.append("JVM memory use " + Utils.formatSize(memUse) + " ");
214 buff.append("Free: " + Utils.formatSize(freeMem) + ", Total: "
215 + Utils.formatSize(totalMem) + ", Max: "
216 + Utils.formatSize(maxMem) + " ");
217
218 if (checkMemory) {
219 String warn = warning != null ? getRangeValue(warning, maxMem,
220 true) : null;
221 String crit = critical != null ? getRangeValue(critical,
222 maxMem, true) : null;
223
224 if (crit != null
225 && ThresholdUtil.isValueInRange(crit, availableMemMb)) {
226 return new ReturnValue(Status.CRITICAL,
227 "Free memory critical: " + availableMemMb
228 + " MB available").withPerformanceData(
229 "memory", new Long(maxMemMb), !critical
230 .contains("%") ? UnitOfMeasure.megabytes
231 : UnitOfMeasure.percentage, warning,
232 critical, 0L, new Long(maxMem));
233 }
234 if (warn != null
235 && ThresholdUtil.isValueInRange(warn, availableMemMb)) {
236 return new ReturnValue(Status.WARNING, "Free memory low: "
237 + availableMem / (1024 * 1024) + " MB available / "
238 + buff.toString()).withPerformanceData("memory",
239 new Long(maxMemMb),
240 !warning.contains("%") ? UnitOfMeasure.megabytes
241 : UnitOfMeasure.percentage, warning,
242 critical, 0L, new Long(maxMem));
243 }
244 }
245
246
247 NodeList connectors = root.getElementsByTagName("connector");
248 for (int i = 0; i < connectors.getLength(); i++) {
249 Element connector = (Element) connectors.item(i);
250 String connectorName = connector.getAttribute("name");
251
252 Element threadInfo = (Element) connector.getElementsByTagName(
253 "threadInfo").item(0);
254 maxThreads = Integer.parseInt(threadInfo
255 .getAttribute("maxThreads"));
256 currentThreadCount = Integer.parseInt(threadInfo
257 .getAttribute("currentThreadCount"));
258 currentThreadsBusy = Integer.parseInt(threadInfo
259 .getAttribute("currentThreadsBusy"));
260 threadsAvailable = maxThreads - currentThreadsBusy;
261 log.debug("Connector " + connectorName + " maxThreads: "
262 + maxThreads + ", currentThreadCount:"
263 + currentThreadCount + ", currentThreadsBusy: "
264 + currentThreadsBusy);
265
266 String msg = connectorName + " - thread count: "
267 + currentThreadCount + ", current threads busy: "
268 + currentThreadsBusy + ", max threads: " + maxThreads;
269
270 if (checkThreads) {
271 String warn = warning != null ? getRangeValue(warning,
272 maxThreads, false) : null;
273 String crit = critical != null ? getRangeValue(critical,
274 maxThreads, false) : null;
275
276 if (critical != null
277 && ThresholdUtil.isValueInRange(crit,
278 threadsAvailable)) {
279 return new ReturnValue(Status.CRITICAL,
280 "CRITICAL - Free " + connectorName
281 + " threads: " + threadsAvailable)
282 .withMessage(msg)
283 .withPerformanceData(
284 connectorName + " threads",
285 new Long(threadsAvailable),
286 !critical.contains("%") ? UnitOfMeasure.counter
287 : UnitOfMeasure.percentage,
288 warning, critical, 0L,
289 new Long(maxThreads));
290 }
291 if (warning != null
292 && ThresholdUtil.isValueInRange(warn,
293 threadsAvailable)) {
294 return new ReturnValue(Status.WARNING,
295 "WARNING - Free " + connectorName
296 + " threads: " + threadsAvailable
297 + ", " + msg).withPerformanceData(
298 connectorName + " threads", new Long(
299 threadsAvailable), !warning
300 .contains("%") ? UnitOfMeasure.counter
301 : UnitOfMeasure.percentage, warning,
302 critical, 0L, new Long(maxThreads));
303 }
304
305 }
306 buff.append(msg);
307 }
308
309 retVal.withMessage(buff.toString());
310 } catch (XPathExpressionException e) {
311 e.printStackTrace();
312
313 } catch (SAXException e) {
314 e.printStackTrace();
315 } catch (IOException e) {
316 e.printStackTrace();
317 }
318
319 return retVal;
320 }
321
322
323
324
325
326
327
328
329
330
331 private long getValue(String value, final int factor, boolean memory) {
332 long val = 0;
333 if (value != null) {
334 if (value.contains("%")) {
335 val = (long) ((factor * Double.parseDouble(value.replace(":",
336 "").replace("%", ""))) / 100);
337 if (memory) {
338 val = val / (1024 * 1024);
339 }
340 } else {
341 val = Long.parseLong(value.replace(":", ""));
342 }
343 }
344 return val;
345
346 }
347
348 private String getRangeValue(String value, int factor, boolean memory) {
349 boolean hadRangeStart = false;
350 boolean hadRangeEnd = false;
351 if (value.endsWith(":")) {
352 hadRangeEnd = true;
353 value = value.substring(0, value.length() - 1);
354 }
355 if (value.startsWith(":")) {
356 hadRangeStart = true;
357 value = value.substring(1, value.length());
358 }
359 String val = "" + getValue(value, factor, memory);
360
361 if (hadRangeStart) {
362 val = ":" + val;
363
364 }
365 if (hadRangeEnd) {
366 val += ":";
367 }
368
369 return val;
370 }
371
372 @Override
373 protected String getPluginName() {
374 return "CHECK_TOMCAT";
375 }
376 }