You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ra...@apache.org on 2020/09/14 14:14:20 UTC
[hbase] branch branch-2 updated: HBASE-25002 Create simple pattern matching query for retrieving metri… (#2370) (#2398)
This is an automated email from the ASF dual-hosted git repository.
ramkrishna pushed a commit to branch branch-2
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-2 by this push:
new 3cb4b29 HBASE-25002 Create simple pattern matching query for retrieving metri… (#2370) (#2398)
3cb4b29 is described below
commit 3cb4b29fa3026103adf76d8a0f7e77b3af93beb6
Author: ramkrish86 <ra...@hotmail.com>
AuthorDate: Mon Sep 14 19:44:00 2020 +0530
HBASE-25002 Create simple pattern matching query for retrieving metri… (#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
---
.../hadoop/hbase/http/jmx/JMXJsonServlet.java | 15 +++++++
.../org/apache/hadoop/hbase/util/JSONBean.java | 52 ++++++++++++++++++----
.../hadoop/hbase/http/jmx/TestJMXJsonServlet.java | 38 ++++++++++++++++
3 files changed, 97 insertions(+), 8 deletions(-)
diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/jmx/JMXJsonServlet.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/jmx/JMXJsonServlet.java
index 3dbf7c3..7e3a79d 100644
--- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/jmx/JMXJsonServlet.java
+++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/jmx/JMXJsonServlet.java
@@ -67,6 +67,21 @@ import org.slf4j.LoggerFactory;
* </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>
diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/util/JSONBean.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/util/JSONBean.java
index c9b18e3..0dbe0fd 100644
--- a/hbase-http/src/main/java/org/apache/hadoop/hbase/util/JSONBean.java
+++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/util/JSONBean.java
@@ -25,6 +25,8 @@ import java.lang.reflect.Array;
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;
@@ -40,18 +42,20 @@ import javax.management.RuntimeMBeanException;
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();
@@ -125,11 +129,12 @@ public class JSONBean {
*/
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;
@@ -149,8 +154,24 @@ public class JSONBean {
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,
@@ -216,7 +237,7 @@ public class JSONBean {
} 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();
@@ -226,7 +247,7 @@ public class JSONBean {
}
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;
}
@@ -237,6 +258,21 @@ public class JSONBean {
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 {
diff --git a/hbase-http/src/test/java/org/apache/hadoop/hbase/http/jmx/TestJMXJsonServlet.java b/hbase-http/src/test/java/org/apache/hadoop/hbase/http/jmx/TestJMXJsonServlet.java
index 9de8b2e..e907a32 100644
--- a/hbase-http/src/test/java/org/apache/hadoop/hbase/http/jmx/TestJMXJsonServlet.java
+++ b/hbase-http/src/test/java/org/apache/hadoop/hbase/http/jmx/TestJMXJsonServlet.java
@@ -66,6 +66,12 @@ public class TestJMXJsonServlet extends HttpServerFunctionalTest {
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);
@@ -116,7 +122,39 @@ public class TestJMXJsonServlet extends HttpServerFunctionalTest {
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