Skip to content

Commit 3cb4b29

Browse files
authored
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
1 parent b0c6305 commit 3cb4b29

File tree

3 files changed

+97
-8
lines changed

3 files changed

+97
-8
lines changed

hbase-http/src/main/java/org/apache/hadoop/hbase/http/jmx/JMXJsonServlet.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,21 @@
6767
* </code> will return the cluster id of the namenode mxbean.
6868
* </p>
6969
* <p>
70+
* If we are not sure on the exact attribute and we want to get all the attributes that match one or
71+
* more given pattern then the format is
72+
* <code>http://.../jmx?get=MXBeanName::*[RegExp1],*[RegExp2]</code>
73+
* </p>
74+
* <p>
75+
* For example
76+
* <code>
77+
* <p>
78+
* http://../jmx?get=Hadoop:service=HBase,name=RegionServer,sub=Tables::[a-zA-z_0-9]*memStoreSize
79+
* </p>
80+
* <p>
81+
* http://../jmx?get=Hadoop:service=HBase,name=RegionServer,sub=Tables::[a-zA-z_0-9]*memStoreSize,[a-zA-z_0-9]*storeFileSize
82+
* </p>
83+
* </code>
84+
* </p>
7085
* If the <code>qry</code> or the <code>get</code> parameter is not formatted
7186
* correctly then a 400 BAD REQUEST http response code will be returned.
7287
* </p>

hbase-http/src/main/java/org/apache/hadoop/hbase/util/JSONBean.java

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import java.nio.charset.StandardCharsets;
2626
import java.util.Iterator;
2727
import java.util.Set;
28+
import java.util.regex.Pattern;
29+
2830
import javax.management.AttributeNotFoundException;
2931
import javax.management.InstanceNotFoundException;
3032
import javax.management.IntrospectionException;
@@ -40,18 +42,20 @@
4042
import javax.management.openmbean.CompositeData;
4143
import javax.management.openmbean.CompositeType;
4244
import javax.management.openmbean.TabularData;
43-
import org.apache.yetus.audience.InterfaceAudience;
44-
import org.slf4j.Logger;
45-
import org.slf4j.LoggerFactory;
4645

4746
import org.apache.hbase.thirdparty.com.google.gson.Gson;
4847
import org.apache.hbase.thirdparty.com.google.gson.stream.JsonWriter;
48+
import org.apache.yetus.audience.InterfaceAudience;
49+
import org.slf4j.Logger;
50+
import org.slf4j.LoggerFactory;
4951

5052
/**
5153
* Utility for doing JSON and MBeans.
5254
*/
5355
@InterfaceAudience.Private
5456
public class JSONBean {
57+
private static final String COMMA = ",";
58+
private static final String ASTERICK = "*";
5559
private static final Logger LOG = LoggerFactory.getLogger(JSONBean.class);
5660
private static final Gson GSON = GsonUtil.createGson().create();
5761

@@ -125,11 +129,12 @@ public int write(MBeanServer mBeanServer, ObjectName qry, String attribute,
125129
*/
126130
private static int write(JsonWriter writer, MBeanServer mBeanServer, ObjectName qry,
127131
String attribute, boolean description) throws IOException {
128-
LOG.trace("Listing beans for " + qry);
132+
LOG.debug("Listing beans for {}", qry);
129133
Set<ObjectName> names = null;
130134
names = mBeanServer.queryNames(qry, null);
131135
writer.name("beans").beginArray();
132136
Iterator<ObjectName> it = names.iterator();
137+
Pattern[] matchingPattern = null;
133138
while (it.hasNext()) {
134139
ObjectName oname = it.next();
135140
MBeanInfo minfo;
@@ -149,8 +154,24 @@ private static int write(JsonWriter writer, MBeanServer mBeanServer, ObjectName
149154
code = (String) mBeanServer.getAttribute(oname, prs);
150155
}
151156
if (attribute != null) {
152-
prs = attribute;
153-
attributeinfo = mBeanServer.getAttribute(oname, prs);
157+
String[] patternAttr = null;
158+
if (attribute.contains(ASTERICK)) {
159+
if (attribute.contains(COMMA)) {
160+
patternAttr = attribute.split(COMMA);
161+
} else {
162+
patternAttr = new String[1];
163+
patternAttr[0] = attribute;
164+
}
165+
matchingPattern = new Pattern[patternAttr.length];
166+
for (int i = 0; i < patternAttr.length; i++) {
167+
matchingPattern[i] = Pattern.compile(patternAttr[i]);
168+
}
169+
// nullify the attribute
170+
attribute = null;
171+
} else {
172+
prs = attribute;
173+
attributeinfo = mBeanServer.getAttribute(oname, prs);
174+
}
154175
}
155176
} catch (RuntimeMBeanException e) {
156177
// UnsupportedOperationExceptions happen in the normal course of business,
@@ -216,7 +237,7 @@ private static int write(JsonWriter writer, MBeanServer mBeanServer, ObjectName
216237
} else {
217238
MBeanAttributeInfo[] attrs = minfo.getAttributes();
218239
for (int i = 0; i < attrs.length; i++) {
219-
writeAttribute(writer, mBeanServer, oname, description, attrs[i]);
240+
writeAttribute(writer, mBeanServer, oname, description, matchingPattern, attrs[i]);
220241
}
221242
}
222243
writer.endObject();
@@ -226,7 +247,7 @@ private static int write(JsonWriter writer, MBeanServer mBeanServer, ObjectName
226247
}
227248

228249
private static void writeAttribute(JsonWriter writer, MBeanServer mBeanServer, ObjectName oname,
229-
boolean description, MBeanAttributeInfo attr) throws IOException {
250+
boolean description, Pattern pattern[], MBeanAttributeInfo attr) throws IOException {
230251
if (!attr.isReadable()) {
231252
return;
232253
}
@@ -237,6 +258,21 @@ private static void writeAttribute(JsonWriter writer, MBeanServer mBeanServer, O
237258
if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0 || attName.indexOf(" ") >= 0) {
238259
return;
239260
}
261+
262+
if (pattern != null) {
263+
boolean matchFound = false;
264+
for (Pattern compile : pattern) {
265+
// check if we have any match
266+
if (compile.matcher(attName).find()) {
267+
matchFound = true;
268+
break;
269+
}
270+
}
271+
if (!matchFound) {
272+
return;
273+
}
274+
}
275+
240276
String descriptionStr = description ? attr.getDescription() : null;
241277
Object value = null;
242278
try {

hbase-http/src/test/java/org/apache/hadoop/hbase/http/jmx/TestJMXJsonServlet.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ public static void assertReFind(String re, String value) {
6666
assertTrue("'"+p+"' does not match "+value, m.find());
6767
}
6868

69+
public static void assertNotFind(String re, String value) {
70+
Pattern p = Pattern.compile(re);
71+
Matcher m = p.matcher(value);
72+
assertFalse("'"+p+"' should not match "+value, m.find());
73+
}
74+
6975
@Test public void testQuery() throws Exception {
7076
String result = readOutput(new URL(baseUrl, "/jmx?qry=java.lang:type=Runtime"));
7177
LOG.info("/jmx?qry=java.lang:type=Runtime RESULT: "+result);
@@ -116,7 +122,39 @@ public static void assertReFind(String re, String value) {
116122
assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result);
117123
assertReFind("\"committed\"\\s*:", result);
118124
assertReFind("\\}\\);$", result);
125+
}
126+
127+
@Test
128+
public void testGetPattern() throws Exception {
129+
// test to get an attribute of a mbean as JSONP
130+
String result = readOutput(
131+
new URL(baseUrl, "/jmx?get=java.lang:type=Memory::[a-zA-z_]*NonHeapMemoryUsage"));
132+
LOG.info("/jmx RESULT: " + result);
133+
assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result);
134+
assertReFind("\"committed\"\\s*:", result);
135+
assertReFind("\"NonHeapMemoryUsage\"\\s*:", result);
136+
assertNotFind("\"HeapMemoryUsage\"\\s*:", result);
119137

138+
result =
139+
readOutput(new URL(baseUrl, "/jmx?get=java.lang:type=Memory::[^Non]*HeapMemoryUsage"));
140+
LOG.info("/jmx RESULT: " + result);
141+
assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result);
142+
assertReFind("\"committed\"\\s*:", result);
143+
assertReFind("\"HeapMemoryUsage\"\\s*:", result);
144+
assertNotFind("\"NonHeapHeapMemoryUsage\"\\s*:", result);
145+
146+
result = readOutput(new URL(baseUrl,
147+
"/jmx?get=java.lang:type=Memory::[a-zA-z_]*HeapMemoryUsage,[a-zA-z_]*NonHeapMemoryUsage"));
148+
LOG.info("/jmx RESULT: " + result);
149+
assertReFind("\"name\"\\s*:\\s*\"java.lang:type=Memory\"", result);
150+
assertReFind("\"committed\"\\s*:", result);
151+
}
152+
153+
@Test
154+
public void testPatternMatching() throws Exception {
155+
assertReFind("[a-zA-z_]*Table1[a-zA-z_]*memStoreSize",
156+
"Namespace_default_table_Table1_metric_memStoreSize");
157+
assertReFind("[a-zA-z_]*memStoreSize", "Namespace_default_table_Table1_metric_memStoreSize");
120158
}
121159

122160
@Test

0 commit comments

Comments
 (0)