HADOOP-7329. Add the capability of getting invividual attribute of a mbean using JMXProxyServlet. (tanping)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1139947 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Tanping Wang 2011-06-26 21:52:43 +00:00
parent 604383b22d
commit 9c83d16c81
3 changed files with 117 additions and 38 deletions

View File

@ -50,6 +50,9 @@ Trunk (unreleased changes)
HADOOP-7206. Support Snappy compression. (Issei Yoshida and HADOOP-7206. Support Snappy compression. (Issei Yoshida and
Alejandro Abdelnur via eli) Alejandro Abdelnur via eli)
HADOOP-7329. Add the capability of getting invividual attribute of a mbean
using JMXProxyServlet. (tanping)
IMPROVEMENTS IMPROVEMENTS
HADOOP-7042. Updates to test-patch.sh to include failed test names and HADOOP-7042. Updates to test-patch.sh to include failed test names and

View File

@ -67,8 +67,20 @@
* For example <code>http://.../jmx?qry=Hadoop:*</code> will return * For example <code>http://.../jmx?qry=Hadoop:*</code> will return
* all hadoop metrics exposed through JMX. * all hadoop metrics exposed through JMX.
* <p> * <p>
* If the <code>qry</code> parameter is not formatted correctly then a * The optional <code>get</code> parameter is used to query an specific
* 400 BAD REQUEST http response code will be returned. * attribute of a JMX bean. The format of the URL is
* <code>http://.../jmx?get=MXBeanName::AttributeName<code>
* <p>
* For example
* <code>
* http://../jmx?get=Hadoop:service=NameNode,name=NameNodeInfo::ClusterId
* </code> will return the cluster id of the namenode mxbean.
* <p>
* If the <code>qry</code> or the <code>get</code> parameter is not formatted
* correctly then a 400 BAD REQUEST http response code will be returned.
* <p>
* If a resouce such as a mbean or attribute can not be found,
* a 404 SC_NOT_FOUND http response code will be returned.
* <p> * <p>
* The return format is JSON and in the form * The return format is JSON and in the form
* <p> * <p>
@ -150,14 +162,36 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) {
jg.writeStringField("result", "ERROR"); jg.writeStringField("result", "ERROR");
jg.writeStringField("message", "No MBeanServer could be found"); jg.writeStringField("message", "No MBeanServer could be found");
jg.close(); jg.close();
LOG.error("No MBeanServer could be found.");
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return; return;
} }
// query per mbean attribute
String getmethod = request.getParameter("get");
if (getmethod != null) {
String[] splitStrings = getmethod.split("\\:\\:");
if (splitStrings.length != 2) {
jg.writeStringField("result", "ERROR");
jg.writeStringField("message", "query format is not as expected.");
jg.close();
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
listBeans(jg, new ObjectName(splitStrings[0]), splitStrings[1],
response);
jg.close();
return;
}
// query per mbean
String qry = request.getParameter("qry"); String qry = request.getParameter("qry");
if (qry == null) { if (qry == null) {
qry = "*:*"; qry = "*:*";
} }
listBeans(jg, new ObjectName(qry)); listBeans(jg, new ObjectName(qry), null, response);
jg.close(); jg.close();
} catch ( IOException e ) { } catch ( IOException e ) {
LOG.error("Caught an exception while processing JMX request", e); LOG.error("Caught an exception while processing JMX request", e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
@ -168,7 +202,9 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) {
} }
// --------------------------------------------------------- Private Methods // --------------------------------------------------------- Private Methods
private void listBeans(JsonGenerator jg, ObjectName qry) throws IOException { private void listBeans(JsonGenerator jg, ObjectName qry, String attribute,
HttpServletResponse response)
throws IOException {
LOG.debug("Listing beans for "+qry); LOG.debug("Listing beans for "+qry);
Set<ObjectName> names = null; Set<ObjectName> names = null;
names = mBeanServer.queryNames(qry, null); names = mBeanServer.queryNames(qry, null);
@ -178,57 +214,84 @@ private void listBeans(JsonGenerator jg, ObjectName qry) throws IOException {
while (it.hasNext()) { while (it.hasNext()) {
ObjectName oname = it.next(); ObjectName oname = it.next();
MBeanInfo minfo; MBeanInfo minfo;
String code; String code = "";
Object attributeinfo = null;
try { try {
minfo = mBeanServer.getMBeanInfo(oname); minfo = mBeanServer.getMBeanInfo(oname);
code = minfo.getClassName(); code = minfo.getClassName();
String prs = "";
try { try {
if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) { if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) {
code = (String) mBeanServer.getAttribute(oname, "modelerType"); prs = "modelerType";
code = (String) mBeanServer.getAttribute(oname, prs);
}
if (attribute!=null) {
prs = attribute;
attributeinfo = mBeanServer.getAttribute(oname, prs);
} }
} catch (AttributeNotFoundException e) { } catch (AttributeNotFoundException e) {
//Ignored the modelerType attribute was not found, so use the class name instead. // If the modelerType attribute was not found, the class name is used
// instead.
LOG.error("getting attribute " + prs + " of " + oname
+ " threw an exception", e);
} catch (MBeanException e) { } catch (MBeanException e) {
//The code inside the attribute getter threw an exception so log it, and // The code inside the attribute getter threw an exception so log it,
// fall back on the class name // and fall back on the class name
LOG.error("getting attribute modelerType of "+oname+" threw an exception", e); LOG.error("getting attribute " + prs + " of " + oname
+ " threw an exception", e);
} catch (RuntimeException e) { } catch (RuntimeException e) {
//For some reason even with an MBeanException available to them Runtime exceptions // For some reason even with an MBeanException available to them
//can still find their way through, so treat them the same as MBeanException // Runtime exceptionscan still find their way through, so treat them
LOG.error("getting attribute modelerType of "+oname+" threw an exception", e); // the same as MBeanException
LOG.error("getting attribute " + prs + " of " + oname
+ " threw an exception", e);
} catch ( ReflectionException e ) { } catch ( ReflectionException e ) {
//This happens when the code inside the JMX bean (setter?? from the java docs) // This happens when the code inside the JMX bean (setter?? from the
//threw an exception, so log it and fall back on the class name // java docs) threw an exception, so log it and fall back on the
LOG.error("getting attribute modelerType of "+oname+" threw an exception", e); // class name
LOG.error("getting attribute " + prs + " of " + oname
+ " threw an exception", e);
} }
} catch (InstanceNotFoundException e) { } catch (InstanceNotFoundException e) {
//Ignored for some reason the bean was not found so don't output it //Ignored for some reason the bean was not found so don't output it
continue; continue;
} catch ( IntrospectionException e ) { } catch ( IntrospectionException e ) {
//This is an internal error, something odd happened with reflection so log it and // This is an internal error, something odd happened with reflection so
//don't output the bean. // log it and don't output the bean.
LOG.error("Problem while trying to process JMX query: "+qry+" with MBean "+oname, e); LOG.error("Problem while trying to process JMX query: " + qry
+ " with MBean " + oname, e);
continue; continue;
} catch ( ReflectionException e ) { } catch ( ReflectionException e ) {
//This happens when the code inside the JMX bean threw an exception, so log it and // This happens when the code inside the JMX bean threw an exception, so
//don't output the bean. // log it and don't output the bean.
LOG.error("Problem while trying to process JMX query: "+qry+" with MBean "+oname, e); LOG.error("Problem while trying to process JMX query: " + qry
+ " with MBean " + oname, e);
continue; continue;
} }
jg.writeStartObject(); jg.writeStartObject();
jg.writeStringField("name", oname.toString()); jg.writeStringField("name", oname.toString());
// can't be null - I think
jg.writeStringField("modelerType", code); jg.writeStringField("modelerType", code);
if ((attribute != null) && (attributeinfo == null)) {
jg.writeStringField("result", "ERROR");
jg.writeStringField("message", "No attribute with name " + attribute
+ " was found.");
jg.writeEndObject();
jg.writeEndArray();
jg.close();
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (attribute != null) {
writeAttribute(jg, attribute, attributeinfo);
} else {
MBeanAttributeInfo attrs[] = minfo.getAttributes(); MBeanAttributeInfo attrs[] = minfo.getAttributes();
for (int i = 0; i < attrs.length; i++) { for (int i = 0; i < attrs.length; i++) {
writeAttribute(jg, oname, attrs[i]); writeAttribute(jg, oname, attrs[i]);
} }
// LOG.error("Caught Error writing value ",t); }
// ExceptionUtils.handleThrowable(t);
//}
jg.writeEndObject(); jg.writeEndObject();
} }
jg.writeEndArray(); jg.writeEndArray();

View File

@ -65,5 +65,18 @@ public static void assertReFind(String re, String value) {
result = readOutput(new URL(baseUrl, "/jmx")); result = readOutput(new URL(baseUrl, "/jmx"));
LOG.info("/jmx RESULT: "+result); LOG.info("/jmx RESULT: "+result);
assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result); assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result);
// test to get an attribute of a mbean
result = readOutput(new URL(baseUrl,
"/jmx?get=java.lang:type=Memory::HeapMemoryUsage"));
LOG.info("/jmx RESULT: "+result);
assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result);
assertReFind("\"committed\"\\s*:", result);
// negative test to get an attribute of a mbean
result = readOutput(new URL(baseUrl,
"/jmx?get=java.lang:type=Memory::"));
LOG.info("/jmx RESULT: "+result);
assertReFind("\"ERROR\"", result);
} }
} }