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