HBASE-12455 Add 'description' to bean and attribute output when you do /jmx?description=true
This commit is contained in:
parent
6c2a299657
commit
804444f892
|
@ -42,14 +42,12 @@ public class BaseSourceImpl implements BaseSource, MetricsSource {
|
||||||
private static enum DefaultMetricsSystemInitializer {
|
private static enum DefaultMetricsSystemInitializer {
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
private boolean inited = false;
|
private boolean inited = false;
|
||||||
private JvmMetrics jvmMetricsSource;
|
|
||||||
|
|
||||||
synchronized void init(String name) {
|
synchronized void init(String name) {
|
||||||
if (inited) return;
|
if (inited) return;
|
||||||
inited = true;
|
inited = true;
|
||||||
DefaultMetricsSystem.initialize(HBASE_METRICS_SYSTEM_NAME);
|
DefaultMetricsSystem.initialize(HBASE_METRICS_SYSTEM_NAME);
|
||||||
jvmMetricsSource = JvmMetrics.initSingleton(name, "");
|
JvmMetrics.initSingleton(name, "");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ import javax.management.ObjectName;
|
||||||
import javax.management.ReflectionException;
|
import javax.management.ReflectionException;
|
||||||
import javax.management.RuntimeMBeanException;
|
import javax.management.RuntimeMBeanException;
|
||||||
import javax.management.RuntimeErrorException;
|
import javax.management.RuntimeErrorException;
|
||||||
import javax.management.RuntimeMBeanException;
|
|
||||||
import javax.management.openmbean.CompositeData;
|
import javax.management.openmbean.CompositeData;
|
||||||
import javax.management.openmbean.CompositeType;
|
import javax.management.openmbean.CompositeType;
|
||||||
import javax.management.openmbean.TabularData;
|
import javax.management.openmbean.TabularData;
|
||||||
|
@ -124,6 +123,12 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final String CALLBACK_PARAM = "callback";
|
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.
|
* MBean server.
|
||||||
|
@ -155,8 +160,7 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest request, HttpServletResponse response) {
|
public void doGet(HttpServletRequest request, HttpServletResponse response) {
|
||||||
try {
|
try {
|
||||||
if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(),
|
if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(), request, response)) {
|
||||||
request, response)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
JsonGenerator jg = null;
|
JsonGenerator jg = null;
|
||||||
|
@ -173,6 +177,9 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
} else {
|
} else {
|
||||||
response.setContentType("application/json; charset=utf8");
|
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 = jsonFactory.createJsonGenerator(writer);
|
||||||
jg.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
|
jg.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
|
||||||
|
@ -190,8 +197,7 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
listBeans(jg, new ObjectName(splitStrings[0]), splitStrings[1],
|
listBeans(jg, new ObjectName(splitStrings[0]), splitStrings[1], description, response);
|
||||||
response);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +206,7 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
if (qry == null) {
|
if (qry == null) {
|
||||||
qry = "*:*";
|
qry = "*:*";
|
||||||
}
|
}
|
||||||
listBeans(jg, new ObjectName(qry), null, response);
|
listBeans(jg, new ObjectName(qry), null, description, response);
|
||||||
} finally {
|
} finally {
|
||||||
if (jg != null) {
|
if (jg != null) {
|
||||||
jg.close();
|
jg.close();
|
||||||
|
@ -222,23 +228,24 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------- Private Methods
|
// --------------------------------------------------------- Private Methods
|
||||||
private void listBeans(JsonGenerator jg, ObjectName qry, String attribute,
|
private void listBeans(JsonGenerator jg, ObjectName qry, String attribute,
|
||||||
HttpServletResponse response)
|
final boolean description, final HttpServletResponse response)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
LOG.trace("Listing beans for "+qry);
|
LOG.trace("Listing beans for "+qry);
|
||||||
Set<ObjectName> names = null;
|
Set<ObjectName> names = null;
|
||||||
names = mBeanServer.queryNames(qry, null);
|
names = mBeanServer.queryNames(qry, null);
|
||||||
|
|
||||||
jg.writeArrayFieldStart("beans");
|
jg.writeArrayFieldStart("beans");
|
||||||
Iterator<ObjectName> it = names.iterator();
|
Iterator<ObjectName> it = names.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
ObjectName oname = it.next();
|
ObjectName oname = it.next();
|
||||||
MBeanInfo minfo;
|
MBeanInfo minfo;
|
||||||
String code = "";
|
String code = "";
|
||||||
|
String descriptionStr = null;
|
||||||
Object attributeinfo = null;
|
Object attributeinfo = null;
|
||||||
try {
|
try {
|
||||||
minfo = mBeanServer.getMBeanInfo(oname);
|
minfo = mBeanServer.getMBeanInfo(oname);
|
||||||
code = minfo.getClassName();
|
code = minfo.getClassName();
|
||||||
|
if (description) descriptionStr = minfo.getDescription();
|
||||||
String prs = "";
|
String prs = "";
|
||||||
try {
|
try {
|
||||||
if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) {
|
if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) {
|
||||||
|
@ -302,12 +309,13 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
|
|
||||||
jg.writeStartObject();
|
jg.writeStartObject();
|
||||||
jg.writeStringField("name", oname.toString());
|
jg.writeStringField("name", oname.toString());
|
||||||
|
if (description && descriptionStr != null && descriptionStr.length() > 0) {
|
||||||
|
jg.writeStringField("description", descriptionStr);
|
||||||
|
}
|
||||||
jg.writeStringField("modelerType", code);
|
jg.writeStringField("modelerType", code);
|
||||||
if ((attribute != null) && (attributeinfo == null)) {
|
if (attribute != null && attributeinfo == null) {
|
||||||
jg.writeStringField("result", "ERROR");
|
jg.writeStringField("result", "ERROR");
|
||||||
jg.writeStringField("message", "No attribute with name " + attribute
|
jg.writeStringField("message", "No attribute with name " + attribute + " was found.");
|
||||||
+ " was found.");
|
|
||||||
jg.writeEndObject();
|
jg.writeEndObject();
|
||||||
jg.writeEndArray();
|
jg.writeEndArray();
|
||||||
jg.close();
|
jg.close();
|
||||||
|
@ -316,11 +324,11 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attribute != null) {
|
if (attribute != null) {
|
||||||
writeAttribute(jg, attribute, attributeinfo);
|
writeAttribute(jg, attribute, descriptionStr, attributeinfo);
|
||||||
} else {
|
} 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, description, attrs[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jg.writeEndObject();
|
jg.writeEndObject();
|
||||||
|
@ -328,7 +336,8 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
jg.writeEndArray();
|
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 {
|
throws IOException {
|
||||||
if (!attr.isReadable()) {
|
if (!attr.isReadable()) {
|
||||||
return;
|
return;
|
||||||
|
@ -337,10 +346,10 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
if ("modelerType".equals(attName)) {
|
if ("modelerType".equals(attName)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0
|
if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0 || attName.indexOf(" ") >= 0) {
|
||||||
|| attName.indexOf(" ") >= 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
String descriptionStr = description? attr.getDescription(): null;
|
||||||
Object value = null;
|
Object value = null;
|
||||||
try {
|
try {
|
||||||
value = mBeanServer.getAttribute(oname, attName);
|
value = mBeanServer.getAttribute(oname, attName);
|
||||||
|
@ -387,15 +396,30 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeAttribute(jg, attName, value);
|
writeAttribute(jg, attName, descriptionStr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeAttribute(JsonGenerator jg, String attName, Object value) throws IOException {
|
private void writeAttribute(JsonGenerator jg, String attName, final String descriptionStr,
|
||||||
jg.writeFieldName(attName);
|
Object value)
|
||||||
writeObject(jg, 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) {
|
if(value == null) {
|
||||||
jg.writeNull();
|
jg.writeNull();
|
||||||
} else {
|
} else {
|
||||||
|
@ -405,7 +429,7 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
int len = Array.getLength(value);
|
int len = Array.getLength(value);
|
||||||
for (int j = 0; j < len; j++) {
|
for (int j = 0; j < len; j++) {
|
||||||
Object item = Array.get(value, j);
|
Object item = Array.get(value, j);
|
||||||
writeObject(jg, item);
|
writeObject(jg, description, item);
|
||||||
}
|
}
|
||||||
jg.writeEndArray();
|
jg.writeEndArray();
|
||||||
} else if(value instanceof Number) {
|
} else if(value instanceof Number) {
|
||||||
|
@ -419,15 +443,15 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
CompositeType comp = cds.getCompositeType();
|
CompositeType comp = cds.getCompositeType();
|
||||||
Set<String> keys = comp.keySet();
|
Set<String> keys = comp.keySet();
|
||||||
jg.writeStartObject();
|
jg.writeStartObject();
|
||||||
for(String key: keys) {
|
for (String key: keys) {
|
||||||
writeAttribute(jg, key, cds.get(key));
|
writeAttribute(jg, key, null, cds.get(key));
|
||||||
}
|
}
|
||||||
jg.writeEndObject();
|
jg.writeEndObject();
|
||||||
} else if(value instanceof TabularData) {
|
} else if(value instanceof TabularData) {
|
||||||
TabularData tds = (TabularData)value;
|
TabularData tds = (TabularData)value;
|
||||||
jg.writeStartArray();
|
jg.writeStartArray();
|
||||||
for(Object entry : tds.values()) {
|
for(Object entry : tds.values()) {
|
||||||
writeObject(jg, entry);
|
writeObject(jg, description, entry);
|
||||||
}
|
}
|
||||||
jg.writeEndArray();
|
jg.writeEndArray();
|
||||||
} else {
|
} else {
|
||||||
|
@ -435,4 +459,4 @@ public class JMXJsonServlet extends HttpServlet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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>
|
uncommented lines. Restart the region server for the changes to take effect.</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section xml:id="discovering.available.metrics">
|
||||||
<title>Discovering Available Metrics</title>
|
<title>Discovering Available Metrics</title>
|
||||||
<para>Rather than listing each metric which HBase emits by default, you can browse through the
|
<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
|
available metrics, either as a JSON output or via JMX. Different metrics are
|
||||||
not include the description field which is included in the JMX view. Different metrics are
|
|
||||||
exposed for the Master process and each region server process.</para>
|
exposed for the Master process and each region server process.</para>
|
||||||
<procedure>
|
<procedure>
|
||||||
<title>Access a JSON Output of Available Metrics</title>
|
<title>Access a JSON Output of Available Metrics</title>
|
||||||
<step>
|
<step>
|
||||||
<para>After starting HBase, access the region server's web UI, at
|
<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>
|
||||||
<step>
|
<step>
|
||||||
<para>Click the <guilabel>Metrics Dump</guilabel> link near the top. The metrics for the region server are
|
<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 — this can be useful when you are exploring
|
||||||
|
what is available — 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>
|
||||||
<step>
|
<step>
|
||||||
<para>To view metrics for the Master, connect to the Master's web UI instead (defaults to
|
<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
|
<literal>http://localhost:60010</literal> or port 16010 in HBase 1.0+) and click its <guilabel>Metrics
|
||||||
Dump</guilabel> link.</para>
|
Dump</guilabel> link.
|
||||||
|
To include metrics descriptions in the listing — this can be useful when you are exploring
|
||||||
|
what is available — 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>
|
</step>
|
||||||
</procedure>
|
</procedure>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue