HBASE-12455 Add 'description' to bean and attribute output when you do /jmx?description=true

This commit is contained in:
stack 2014-11-11 12:59:30 -08:00
parent 6c2a299657
commit 804444f892
3 changed files with 72 additions and 38 deletions

View File

@ -42,14 +42,12 @@ public class BaseSourceImpl implements BaseSource, MetricsSource {
private static enum DefaultMetricsSystemInitializer {
INSTANCE;
private boolean inited = false;
private JvmMetrics jvmMetricsSource;
synchronized void init(String name) {
if (inited) return;
inited = true;
DefaultMetricsSystem.initialize(HBASE_METRICS_SYSTEM_NAME);
jvmMetricsSource = JvmMetrics.initSingleton(name, "");
JvmMetrics.initSingleton(name, "");
}
}

View File

@ -36,7 +36,6 @@ import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.RuntimeMBeanException;
import javax.management.RuntimeErrorException;
import javax.management.RuntimeMBeanException;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularData;
@ -124,6 +123,12 @@ public class JMXJsonServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String CALLBACK_PARAM = "callback";
/**
* If query string includes 'description', then we will emit bean and attribute descriptions to
* output IFF they are not null and IFF the description is not the same as the attribute name:
* i.e. specify an URL like so: /jmx?description=true
*/
private static final String INCLUDE_DESCRIPTION = "description";
/**
* MBean server.
@ -155,8 +160,7 @@ public class JMXJsonServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
try {
if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(),
request, response)) {
if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(), request, response)) {
return;
}
JsonGenerator jg = null;
@ -173,6 +177,9 @@ public class JMXJsonServlet extends HttpServlet {
} else {
response.setContentType("application/json; charset=utf8");
}
// Should we output description on each attribute and bean?
String tmpStr = request.getParameter(INCLUDE_DESCRIPTION);
boolean description = tmpStr != null && tmpStr.length() > 0;
jg = jsonFactory.createJsonGenerator(writer);
jg.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
@ -190,8 +197,7 @@ public class JMXJsonServlet extends HttpServlet {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
listBeans(jg, new ObjectName(splitStrings[0]), splitStrings[1],
response);
listBeans(jg, new ObjectName(splitStrings[0]), splitStrings[1], description, response);
return;
}
@ -200,7 +206,7 @@ public class JMXJsonServlet extends HttpServlet {
if (qry == null) {
qry = "*:*";
}
listBeans(jg, new ObjectName(qry), null, response);
listBeans(jg, new ObjectName(qry), null, description, response);
} finally {
if (jg != null) {
jg.close();
@ -222,23 +228,24 @@ public class JMXJsonServlet extends HttpServlet {
}
// --------------------------------------------------------- Private Methods
private void listBeans(JsonGenerator jg, ObjectName qry, String attribute,
HttpServletResponse response)
private void listBeans(JsonGenerator jg, ObjectName qry, String attribute,
final boolean description, final HttpServletResponse response)
throws IOException {
LOG.trace("Listing beans for "+qry);
Set<ObjectName> names = null;
names = mBeanServer.queryNames(qry, null);
jg.writeArrayFieldStart("beans");
Iterator<ObjectName> it = names.iterator();
while (it.hasNext()) {
ObjectName oname = it.next();
MBeanInfo minfo;
String code = "";
String descriptionStr = null;
Object attributeinfo = null;
try {
minfo = mBeanServer.getMBeanInfo(oname);
code = minfo.getClassName();
if (description) descriptionStr = minfo.getDescription();
String prs = "";
try {
if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) {
@ -302,12 +309,13 @@ public class JMXJsonServlet extends HttpServlet {
jg.writeStartObject();
jg.writeStringField("name", oname.toString());
if (description && descriptionStr != null && descriptionStr.length() > 0) {
jg.writeStringField("description", descriptionStr);
}
jg.writeStringField("modelerType", code);
if ((attribute != null) && (attributeinfo == null)) {
if (attribute != null && attributeinfo == null) {
jg.writeStringField("result", "ERROR");
jg.writeStringField("message", "No attribute with name " + attribute
+ " was found.");
jg.writeStringField("message", "No attribute with name " + attribute + " was found.");
jg.writeEndObject();
jg.writeEndArray();
jg.close();
@ -316,11 +324,11 @@ public class JMXJsonServlet extends HttpServlet {
}
if (attribute != null) {
writeAttribute(jg, attribute, attributeinfo);
writeAttribute(jg, attribute, descriptionStr, attributeinfo);
} else {
MBeanAttributeInfo attrs[] = minfo.getAttributes();
for (int i = 0; i < attrs.length; i++) {
writeAttribute(jg, oname, attrs[i]);
writeAttribute(jg, oname, description, attrs[i]);
}
}
jg.writeEndObject();
@ -328,7 +336,8 @@ public class JMXJsonServlet extends HttpServlet {
jg.writeEndArray();
}
private void writeAttribute(JsonGenerator jg, ObjectName oname, MBeanAttributeInfo attr)
private void writeAttribute(JsonGenerator jg, ObjectName oname, final boolean description,
MBeanAttributeInfo attr)
throws IOException {
if (!attr.isReadable()) {
return;
@ -337,10 +346,10 @@ public class JMXJsonServlet extends HttpServlet {
if ("modelerType".equals(attName)) {
return;
}
if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0
|| attName.indexOf(" ") >= 0) {
if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0 || attName.indexOf(" ") >= 0) {
return;
}
String descriptionStr = description? attr.getDescription(): null;
Object value = null;
try {
value = mBeanServer.getAttribute(oname, attName);
@ -387,15 +396,30 @@ public class JMXJsonServlet extends HttpServlet {
return;
}
writeAttribute(jg, attName, value);
writeAttribute(jg, attName, descriptionStr, value);
}
private void writeAttribute(JsonGenerator jg, String attName, Object value) throws IOException {
jg.writeFieldName(attName);
writeObject(jg, value);
private void writeAttribute(JsonGenerator jg, String attName, final String descriptionStr,
Object value)
throws IOException {
boolean description = false;
if (descriptionStr != null && descriptionStr.length() > 0 && !attName.equals(descriptionStr)) {
description = true;
jg.writeFieldName(attName);
jg.writeStartObject();
jg.writeFieldName("description");
jg.writeString(descriptionStr);
jg.writeFieldName("value");
writeObject(jg, description, value);
jg.writeEndObject();
} else {
jg.writeFieldName(attName);
writeObject(jg, description, value);
}
}
private void writeObject(JsonGenerator jg, Object value) throws IOException {
private void writeObject(JsonGenerator jg, final boolean description, Object value)
throws IOException {
if(value == null) {
jg.writeNull();
} else {
@ -405,7 +429,7 @@ public class JMXJsonServlet extends HttpServlet {
int len = Array.getLength(value);
for (int j = 0; j < len; j++) {
Object item = Array.get(value, j);
writeObject(jg, item);
writeObject(jg, description, item);
}
jg.writeEndArray();
} else if(value instanceof Number) {
@ -419,15 +443,15 @@ public class JMXJsonServlet extends HttpServlet {
CompositeType comp = cds.getCompositeType();
Set<String> keys = comp.keySet();
jg.writeStartObject();
for(String key: keys) {
writeAttribute(jg, key, cds.get(key));
for (String key: keys) {
writeAttribute(jg, key, null, cds.get(key));
}
jg.writeEndObject();
} else if(value instanceof TabularData) {
TabularData tds = (TabularData)value;
jg.writeStartArray();
for(Object entry : tds.values()) {
writeObject(jg, entry);
writeObject(jg, description, entry);
}
jg.writeEndArray();
} else {
@ -435,4 +459,4 @@ public class JMXJsonServlet extends HttpServlet {
}
}
}
}
}

View File

@ -1015,26 +1015,38 @@ $ for i in `cat conf/regionservers|sort`; do ./bin/graceful_stop.sh --restart --
uncommented lines. Restart the region server for the changes to take effect.</para>
</section>
<section>
<section xml:id="discovering.available.metrics">
<title>Discovering Available Metrics</title>
<para>Rather than listing each metric which HBase emits by default, you can browse through the
available metrics, either as a JSON output or via JMX. At this time, the JSON output does
not include the description field which is included in the JMX view. Different metrics are
available metrics, either as a JSON output or via JMX. Different metrics are
exposed for the Master process and each region server process.</para>
<procedure>
<title>Access a JSON Output of Available Metrics</title>
<step>
<para>After starting HBase, access the region server's web UI, at
<literal>http://localhost:60030</literal> by default.</para>
<literal>http://REGIONSERVER_HOSTNAME:60030</literal> by default (or port 16030 in HBase 1.0+).</para>
</step>
<step>
<para>Click the <guilabel>Metrics Dump</guilabel> link near the top. The metrics for the region server are
presented as a dump of the JMX bean in JSON format.</para>
presented as a dump of the JMX bean in JSON format. This will dump out all metrics names and their
values.
To include metrics descriptions in the listing &mdash; this can be useful when you are exploring
what is available &mdash; add a query string of
<literal>?description=true</literal> so your URL becomes
<literal>http://REGIONSERVER_HOSTNAME:60030/jmx?description=true</literal>.
Not all beans and attributes have descriptions.
</para>
</step>
<step>
<para>To view metrics for the Master, connect to the Master's web UI instead (defaults to
<literal>http://localhost:60010</literal>) and click its <guilabel>Metrics
Dump</guilabel> link.</para>
<literal>http://localhost:60010</literal> or port 16010 in HBase 1.0+) and click its <guilabel>Metrics
Dump</guilabel> link.
To include metrics descriptions in the listing &mdash; this can be useful when you are exploring
what is available &mdash; add a query string of
<literal>?description=true</literal> so your URL becomes
<literal>http://REGIONSERVER_HOSTNAME:60010/jmx?description=true</literal>.
Not all beans and attributes have descriptions.
</para>
</step>
</procedure>