Skip to content

Commit

Permalink
HBASE-25002 Create simple pattern matching query for retrieving metri… (
Browse files Browse the repository at this point in the history
#2370) (#2398)

* HBASE-25002 Create simple pattern matching query for retrieving metrics matching the pattern

* Address review comments

* Final set of comments addressed

* Address checkstyle comments
  • Loading branch information
ramkrish86 authored Sep 14, 2020
1 parent b0c6305 commit 3cb4b29
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@
* </code> will return the cluster id of the namenode mxbean.
* </p>
* <p>
* If we are not sure on the exact attribute and we want to get all the attributes that match one or
* more given pattern then the format is
* <code>http://.../jmx?get=MXBeanName::*[RegExp1],*[RegExp2]</code>
* </p>
* <p>
* For example
* <code>
* <p>
* http://../jmx?get=Hadoop:service=HBase,name=RegionServer,sub=Tables::[a-zA-z_0-9]*memStoreSize
* </p>
* <p>
* http://../jmx?get=Hadoop:service=HBase,name=RegionServer,sub=Tables::[a-zA-z_0-9]*memStoreSize,[a-zA-z_0-9]*storeFileSize
* </p>
* </code>
* </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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;
import java.util.regex.Pattern;

import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
Expand All @@ -40,18 +42,20 @@
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.TabularData;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.hbase.thirdparty.com.google.gson.Gson;
import org.apache.hbase.thirdparty.com.google.gson.stream.JsonWriter;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Utility for doing JSON and MBeans.
*/
@InterfaceAudience.Private
public class JSONBean {
private static final String COMMA = ",";
private static final String ASTERICK = "*";
private static final Logger LOG = LoggerFactory.getLogger(JSONBean.class);
private static final Gson GSON = GsonUtil.createGson().create();

Expand Down Expand Up @@ -125,11 +129,12 @@ public int write(MBeanServer mBeanServer, ObjectName qry, String attribute,
*/
private static int write(JsonWriter writer, MBeanServer mBeanServer, ObjectName qry,
String attribute, boolean description) throws IOException {
LOG.trace("Listing beans for " + qry);
LOG.debug("Listing beans for {}", qry);
Set<ObjectName> names = null;
names = mBeanServer.queryNames(qry, null);
writer.name("beans").beginArray();
Iterator<ObjectName> it = names.iterator();
Pattern[] matchingPattern = null;
while (it.hasNext()) {
ObjectName oname = it.next();
MBeanInfo minfo;
Expand All @@ -149,8 +154,24 @@ private static int write(JsonWriter writer, MBeanServer mBeanServer, ObjectName
code = (String) mBeanServer.getAttribute(oname, prs);
}
if (attribute != null) {
prs = attribute;
attributeinfo = mBeanServer.getAttribute(oname, prs);
String[] patternAttr = null;
if (attribute.contains(ASTERICK)) {
if (attribute.contains(COMMA)) {
patternAttr = attribute.split(COMMA);
} else {
patternAttr = new String[1];
patternAttr[0] = attribute;
}
matchingPattern = new Pattern[patternAttr.length];
for (int i = 0; i < patternAttr.length; i++) {
matchingPattern[i] = Pattern.compile(patternAttr[i]);
}
// nullify the attribute
attribute = null;
} else {
prs = attribute;
attributeinfo = mBeanServer.getAttribute(oname, prs);
}
}
} catch (RuntimeMBeanException e) {
// UnsupportedOperationExceptions happen in the normal course of business,
Expand Down Expand Up @@ -216,7 +237,7 @@ private static int write(JsonWriter writer, MBeanServer mBeanServer, ObjectName
} else {
MBeanAttributeInfo[] attrs = minfo.getAttributes();
for (int i = 0; i < attrs.length; i++) {
writeAttribute(writer, mBeanServer, oname, description, attrs[i]);
writeAttribute(writer, mBeanServer, oname, description, matchingPattern, attrs[i]);
}
}
writer.endObject();
Expand All @@ -226,7 +247,7 @@ private static int write(JsonWriter writer, MBeanServer mBeanServer, ObjectName
}

private static void writeAttribute(JsonWriter writer, MBeanServer mBeanServer, ObjectName oname,
boolean description, MBeanAttributeInfo attr) throws IOException {
boolean description, Pattern pattern[], MBeanAttributeInfo attr) throws IOException {
if (!attr.isReadable()) {
return;
}
Expand All @@ -237,6 +258,21 @@ private static void writeAttribute(JsonWriter writer, MBeanServer mBeanServer, O
if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0 || attName.indexOf(" ") >= 0) {
return;
}

if (pattern != null) {
boolean matchFound = false;
for (Pattern compile : pattern) {
// check if we have any match
if (compile.matcher(attName).find()) {
matchFound = true;
break;
}
}
if (!matchFound) {
return;
}
}

String descriptionStr = description ? attr.getDescription() : null;
Object value = null;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ public static void assertReFind(String re, String value) {
assertTrue("'"+p+"' does not match "+value, m.find());
}

public static void assertNotFind(String re, String value) {
Pattern p = Pattern.compile(re);
Matcher m = p.matcher(value);
assertFalse("'"+p+"' should not match "+value, m.find());
}

@Test public void testQuery() throws Exception {
String result = readOutput(new URL(baseUrl, "/jmx?qry=java.lang:type=Runtime"));
LOG.info("/jmx?qry=java.lang:type=Runtime RESULT: "+result);
Expand Down Expand Up @@ -116,7 +122,39 @@ public static void assertReFind(String re, String value) {
assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result);
assertReFind("\"committed\"\\s*:", result);
assertReFind("\\}\\);$", result);
}

@Test
public void testGetPattern() throws Exception {
// test to get an attribute of a mbean as JSONP
String result = readOutput(
new URL(baseUrl, "/jmx?get=java.lang:type=Memory::[a-zA-z_]*NonHeapMemoryUsage"));
LOG.info("/jmx RESULT: " + result);
assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result);
assertReFind("\"committed\"\\s*:", result);
assertReFind("\"NonHeapMemoryUsage\"\\s*:", result);
assertNotFind("\"HeapMemoryUsage\"\\s*:", result);

result =
readOutput(new URL(baseUrl, "/jmx?get=java.lang:type=Memory::[^Non]*HeapMemoryUsage"));
LOG.info("/jmx RESULT: " + result);
assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result);
assertReFind("\"committed\"\\s*:", result);
assertReFind("\"HeapMemoryUsage\"\\s*:", result);
assertNotFind("\"NonHeapHeapMemoryUsage\"\\s*:", result);

result = readOutput(new URL(baseUrl,
"/jmx?get=java.lang:type=Memory::[a-zA-z_]*HeapMemoryUsage,[a-zA-z_]*NonHeapMemoryUsage"));
LOG.info("/jmx RESULT: " + result);
assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result);
assertReFind("\"committed\"\\s*:", result);
}

@Test
public void testPatternMatching() throws Exception {
assertReFind("[a-zA-z_]*Table1[a-zA-z_]*memStoreSize",
"Namespace_default_table_Table1_metric_memStoreSize");
assertReFind("[a-zA-z_]*memStoreSize", "Namespace_default_table_Table1_metric_memStoreSize");
}

@Test
Expand Down

0 comments on commit 3cb4b29

Please sign in to comment.