Repository: hbase Updated Branches: refs/heads/master 99221bd43 -> 193a98033
HBASE-15943 Add page displaying JVM process metrics Signed-off-by: Michael Stack <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/193a9803 Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/193a9803 Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/193a9803 Branch: refs/heads/master Commit: 193a980338b6a9e4fa37ea675d4fad74fc8705e3 Parents: 99221bd Author: samirMop <[email protected]> Authored: Mon Jul 3 13:00:45 2017 +0200 Committer: Michael Stack <[email protected]> Committed: Mon Jul 3 21:35:27 2017 -0700 ---------------------------------------------------------------------- .../hbase/tmpl/master/MasterStatusTmpl.jamon | 1 + .../hbase/tmpl/regionserver/RSStatusTmpl.jamon | 1 + .../hadoop/hbase/util/JSONMetricUtil.java | 214 +++++++++++++++++ .../hbase-webapps/master/procedures.jsp | 1 + .../hbase-webapps/master/processMaster.jsp | 228 ++++++++++++++++++ .../hbase-webapps/master/processRS.jsp | 230 +++++++++++++++++++ .../resources/hbase-webapps/master/snapshot.jsp | 1 + .../resources/hbase-webapps/master/table.jsp | 1 + .../hbase-webapps/master/tablesDetailed.jsp | 1 + .../main/resources/hbase-webapps/master/zk.jsp | 1 + .../hbase-webapps/regionserver/processRS.jsp | 230 +++++++++++++++++++ .../hbase-webapps/regionserver/region.jsp | 1 + .../hadoop/hbase/util/TestJSONMetricUtil.java | 106 +++++++++ 13 files changed, 1016 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon index 58ae3eb..708e72d 100644 --- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon +++ b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon @@ -128,6 +128,7 @@ AssignmentManager assignmentManager = master.getAssignmentManager(); <%if master.isActiveMaster() %> <li><a href="/procedures.jsp">Procedures & Locks</a></li> </%if> + <li><a href="/processMaster.jsp">Process Metrics</a></li> <li><a href="/logs/">Local Logs</a></li> <li><a href="/logLevel">Log Level</a></li> <li><a href="/dump">Debug Dump</a></li> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RSStatusTmpl.jamon ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RSStatusTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RSStatusTmpl.jamon index 3a68d96..7219c0a 100644 --- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RSStatusTmpl.jamon +++ b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RSStatusTmpl.jamon @@ -81,6 +81,7 @@ org.apache.hadoop.hbase.zookeeper.MasterAddressTracker; <div class="collapse navbar-collapse"> <ul class="nav navbar-nav"> <li class="active"><a href="/">Home</a></li> + <li><a href="/processRS.jsp">Process Metrics</a></li> <li><a href="/logs/">Local Logs</a></li> <li><a href="/logLevel">Log Level</a></li> <li><a href="/dump">Debug Dump</a></li> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/java/org/apache/hadoop/hbase/util/JSONMetricUtil.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/JSONMetricUtil.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/JSONMetricUtil.java new file mode 100644 index 0000000..f64934e --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/JSONMetricUtil.java @@ -0,0 +1,214 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ +package org.apache.hadoop.hbase.util; + +import java.beans.IntrospectionException; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.RuntimeMXBean; +import java.util.Hashtable; +import java.util.List; +import java.util.Set; + +import javax.management.InstanceNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.openmbean.CompositeData; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.JsonProcessingException; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jettison.json.JSONException; + +public final class JSONMetricUtil { + + private static final Log LOG = LogFactory.getLog(JSONMetricUtil.class); + + private static MBeanServer mbServer = ManagementFactory.getPlatformMBeanServer(); + //MBeans ObjectName domain names + public static final String JAVA_LANG_DOMAIN = "java.lang"; + public static final String JAVA_NIO_DOMAIN = "java.nio"; + public static final String SUN_MGMT_DOMAIN = "com.sun.management"; + public static final String HADOOP_DOMAIN = "Hadoop"; + + //MBeans ObjectName properties key names + public static final String TYPE_KEY = "type"; + public static final String NAME_KEY = "name"; + public static final String SERVICE_KEY = "service"; + public static final String SUBSYSTEM_KEY = "sub"; + +/** + * Utility for getting metric values. Collection of static methods intended for + * easier access to metric values. + */ + private JSONMetricUtil() { + // Not to be called + } + + public static MBeanAttributeInfo[] getMBeanAttributeInfo(ObjectName bean) + throws IntrospectionException, InstanceNotFoundException, ReflectionException, + IntrospectionException, javax.management.IntrospectionException { + MBeanInfo mbinfo = mbServer.getMBeanInfo(bean); + return mbinfo.getAttributes(); + } + + public static Object getValueFromMBean(ObjectName bean, String attribute) { + Object value = null; + try { + value = mbServer.getAttribute(bean, attribute); + } + catch(Exception e) { + LOG.error("Unable to get value from MBean= "+ bean.toString() + + "for attribute=" + attribute + " " + e.getMessage()); + } + return value; + } + + /** + * Returns a subset of mbeans defined by qry. + * Modeled after {@link JSONBean#dumpRegionServerMetrics()} + * Example: String qry= "java.lang:type=Memory" + * @throws MalformedObjectNameException if json have bad format + * @throws IOException / + * @return String representation of json array. + */ + public static String dumpBeanToString(String qry) throws MalformedObjectNameException, + IOException { + StringWriter sw = new StringWriter(1024 * 100); // Guess this size + try (PrintWriter writer = new PrintWriter(sw)) { + JSONBean dumper = new JSONBean(); + try (JSONBean.Writer jsonBeanWriter = dumper.open(writer)) { + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); + jsonBeanWriter.write(mbeanServer, + new ObjectName(qry), null, false); + } + } + sw.close(); + return sw.toString(); + } + + public static JsonNode mappStringToJsonNode(String jsonString) throws + JsonProcessingException, IOException { + ObjectMapper mapper = new ObjectMapper(); + JsonNode node = mapper.readTree(jsonString); + return node; + } + + + public static JsonNode searchJson(JsonNode tree, String searchKey) + throws JsonProcessingException, IOException { + if (tree == null) { + return null; + } + if(tree.has(searchKey)) { + return tree.get(searchKey); + } + if(tree.isContainerNode()) { + for(JsonNode branch: tree) { + JsonNode branchResult = searchJson(branch, searchKey); + if (branchResult != null && !branchResult.isMissingNode()) { + return branchResult; + } + } + } + return null; + } + + /** + * Method for building hashtable used for constructing ObjectName. + * Mapping is done with arrays indices + * @param keys Hashtable keys + * @param values Hashtable values + * @return Hashtable or null if arrays are empty * or have different number of elements + */ + public static Hashtable<String, String> buldKeyValueTable(String[] keys, String[] values) { + if (keys.length != values.length) { + LOG.error("keys and values arrays must be same size"); + return null; + } + if (keys.length == 0 || values.length == 0) { + LOG.error("keys and values arrays can not be empty;"); + return null; + } + Hashtable<String, String> table = new Hashtable<String, String>(); + for(int i = 0; i < keys.length; i++) { + table.put(keys[i], values[i]); + } + return table; + } + + public static ObjectName buildObjectName(String pattern) throws MalformedObjectNameException { + return new ObjectName(pattern); + } + + public static ObjectName buildObjectName(String domain, Hashtable<String, String> keyValueTable) + throws MalformedObjectNameException { + return new ObjectName(domain, keyValueTable); + } + + public static Set<ObjectName> getRegistredMBeans(ObjectName name, MBeanServer mbs) { + return mbs.queryNames(name, null); + } + + public static String getProcessPID() { + return ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; + } + + public static String getCommmand() throws MalformedObjectNameException, + IOException, JSONException { + RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); + return runtimeBean.getSystemProperties().get("sun.java.command"); + } + + public static List<GarbageCollectorMXBean> getGcCollectorBeans() { + List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); + return gcBeans; + } + + public static long getLastGcDuration(ObjectName gcCollector) { + long lastGcDuration = 0; + Object lastGcInfo = getValueFromMBean(gcCollector, "LastGcInfo"); + if (lastGcInfo != null && lastGcInfo instanceof CompositeData) { + CompositeData cds = (CompositeData)lastGcInfo; + lastGcDuration = (long) cds.get("duration"); + } + return lastGcDuration; + } + + public static List<MemoryPoolMXBean> getMemoryPools() { + List<MemoryPoolMXBean> mPools = ManagementFactory.getMemoryPoolMXBeans(); + return mPools; + } + + public static float calcPercentage(long a, long b) { + if (a == 0 || b == 0) { + return 0; + } + return ((float)a / (float)b) *100; + } +} http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/resources/hbase-webapps/master/procedures.jsp ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/resources/hbase-webapps/master/procedures.jsp b/hbase-server/src/main/resources/hbase-webapps/master/procedures.jsp index b686114..00d8ead 100644 --- a/hbase-server/src/main/resources/hbase-webapps/master/procedures.jsp +++ b/hbase-server/src/main/resources/hbase-webapps/master/procedures.jsp @@ -91,6 +91,7 @@ <li><a href="/master-status">Home</a></li> <li><a href="/tablesDetailed.jsp">Table Details</a></li> <li><a href="/procedures.jsp">Procedures & Locks</a></li> + <li><a href="/processMaster.jsp">Process Metrics</a></li> <li><a href="/logs/">Local Logs</a></li> <li><a href="/logLevel">Log Level</a></li> <li><a href="/dump">Debug Dump</a></li> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/resources/hbase-webapps/master/processMaster.jsp ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/resources/hbase-webapps/master/processMaster.jsp b/hbase-server/src/main/resources/hbase-webapps/master/processMaster.jsp new file mode 100644 index 0000000..b1211b9 --- /dev/null +++ b/hbase-server/src/main/resources/hbase-webapps/master/processMaster.jsp @@ -0,0 +1,228 @@ +<%-- +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--%> +<%@ page contentType="text/html;charset=UTF-8" + import="java.util.Date" + import="java.util.List" + import="org.apache.hadoop.hbase.HBaseConfiguration" + import="static org.apache.commons.lang.StringEscapeUtils.escapeXml" + import="javax.management.ObjectName" + import="java.lang.management.ManagementFactory" + import="java.lang.management.MemoryPoolMXBean" + import="java.lang.management.RuntimeMXBean" + import="java.lang.management.GarbageCollectorMXBean" + import="org.apache.hadoop.hbase.util.JSONMetricUtil" + import="org.apache.hadoop.hbase.procedure2.util.StringUtils" + import="org.codehaus.jackson.JsonNode" +%> +<% +RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); +ObjectName jvmMetrics = new ObjectName("Hadoop:service=HBase,name=JvmMetrics"); + +// There is always two of GC collectors +List<GarbageCollectorMXBean> gcBeans = JSONMetricUtil.getGcCollectorBeans(); +GarbageCollectorMXBean collector1 = null; +GarbageCollectorMXBean collector2 = null; +try { +collector1 = gcBeans.get(0); +collector2 = gcBeans.get(1); +} catch(IndexOutOfBoundsException e) {} +List<MemoryPoolMXBean> mPools = JSONMetricUtil.getMemoryPools(); +%> +<!--[if IE]> +<!DOCTYPE html> +<![endif]--> +<?xml version="1.0" encoding="UTF-8" ?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta charset="utf-8"> + <title>Process info for PID: <%= JSONMetricUtil.getProcessPID() %></title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content=""> + + <link href="/static/css/bootstrap.min.css" rel="stylesheet"> + <link href="/static/css/bootstrap-theme.min.css" rel="stylesheet"> + <link href="/static/css/hbase.css" rel="stylesheet"> +</head> +<body> +<div class="navbar navbar-fixed-top navbar-default"> + <div class="container-fluid"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="/rs-status"><img src="/static/hbase_logo_small.png" alt="HBase Logo"/></a> + </div> + <div class="collapse navbar-collapse"> + <ul class="nav navbar-nav"> + <li><a href="/master-status">Home</a></li> + <li><a href="/tablesDetailed.jsp">Table Details</a></li> + <li><a href="/procedures.jsp">Procedures</a></li> + <li><a href="/processMaster.jsp">Process Metrics</a></li> + <li><a href="/logs/">Local Logs</a></li> + <li><a href="/logLevel">Log Level</a></li> + <li><a href="/dump">Debug Dump</a></li> + <li><a href="/jmx">Metrics Dump</a></li> + <% if (HBaseConfiguration.isShowConfInServlet()) { %> + <li><a href="/conf">HBase Configuration</a></li> + <% } %> + </ul> + </div><!--/.nav-collapse --> + </div> +</div> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h1><%= JSONMetricUtil.getCommmand().split(" ")[0] %></h1> + </div> + </div> + <table class="table table-striped" width="90%" > + <tr> + <th>Started</th> + <th>Uptime</th> + <th>PID</th> + <th>Owner</th> + </tr> + <tr> + <tr> + <td><%= new Date(runtimeBean.getStartTime()) %></a></td> + <td><%= StringUtils.humanTimeDiff(runtimeBean.getUptime()) %></a></td> + <td><%= JSONMetricUtil.getProcessPID() %></a></td> + <td><%= runtimeBean.getSystemProperties().get("user.name") %></a></td> + </tr> + </table> +</div> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h2>Threads</h2> + </div> + </div> + <table class="table table-striped" width="90%" > + <tr> + <th>ThreadsNew</th> + <th>ThreadsRunable</th> + <th>ThreadsBlocked</th> + <th>ThreadsWaiting</th> + <th>ThreadsTimeWaiting</th> + <th>ThreadsTerminated</th> + </tr> + <tr> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsNew") %></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsRunnable")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsBlocked")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsWaiting")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsTimedWaiting")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsTerminated")%></a></td> + </tr> + </table> +</div> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h2>GC Collectors</h2> + </div> + </div> + <% if (gcBeans.size() == 2) { %> +<div class="tabbable"> + <ul class="nav nav-pills"> + <li class="active"> + <a href="#tab_gc1" data-toggle="tab"><%=collector1.getName() %></a> + </li> + <li class=""> + <a href="#tab_gc2" data-toggle="tab"><%=collector2.getName() %></a> + </li> + </ul> + <div class="tab-content" style="padding-bottom: 9px; border-bottom: 1px solid #ddd;"> + <div class="tab-pane active" id="tab_gc1"> + <table class="table table-striped"> + <tr> + <th>Collection Count</th> + <th>Collection Time</th> + <th>Last duration</th> + </tr> + <tr> + <td> <%= collector1.getCollectionCount() %></td> + <td> <%= StringUtils.humanTimeDiff(collector1.getCollectionTime()) %> </td> + <td> <%= StringUtils.humanTimeDiff(JSONMetricUtil.getLastGcDuration( + collector1.getObjectName())) %></td> + </tr> + </table> + </div> + <div class="tab-pane" id="tab_gc2"> + <table class="table table-striped"> + <tr> + <th>Collection Count</th> + <th>Collection Time</th> + <th>Last duration</th> + </tr> + <tr> + <td> <%= collector2.getCollectionCount() %></td> + <td> <%= StringUtils.humanTimeDiff(collector2.getCollectionTime()) %> </td> + <td> <%= StringUtils.humanTimeDiff(JSONMetricUtil.getLastGcDuration( + collector2.getObjectName())) %></td> + </tr> + </table> + </div> + </div> + </div> + <%} else { %> + <p> Can not display GC Collector stats.</p> + <%} %> + Total GC Collection time: <%= StringUtils.humanTimeDiff(collector1.getCollectionTime() + + collector2.getCollectionTime())%> +</div> +<% for(MemoryPoolMXBean mp:mPools) { +if(mp.getName().contains("Cache")) continue;%> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h2><%= mp.getName() %></h2> + </div> + </div> + <table class="table table-striped" width="90%" > + <tr> + <th>Commited</th> + <th>Init</th> + <th>Max</th> + <th>Used</th> + <th>Utilization [%]</th> + </tr> + <tr> + <tr> + <td><%= StringUtils.humanSize(mp.getUsage().getCommitted()) %></a></td> + <td><%= StringUtils.humanSize(mp.getUsage().getInit())%></a></td> + <td><%= StringUtils.humanSize(mp.getUsage().getMax())%></a></td> + <td><%= StringUtils.humanSize(mp.getUsage().getUsed())%></a></td> + <td><%= JSONMetricUtil.calcPercentage(mp.getUsage().getUsed(), + mp.getUsage().getCommitted()) %></a></td> + </tr> + </table> +</div> +<% } %> + +<script src="/static/js/jquery.min.js" type="text/javascript"></script> +<script src="/static/js/bootstrap.min.js" type="text/javascript"></script> +<script src="/static/js/tab.js" type="text/javascript"></script> + +</body> +</html> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/resources/hbase-webapps/master/processRS.jsp ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/resources/hbase-webapps/master/processRS.jsp b/hbase-server/src/main/resources/hbase-webapps/master/processRS.jsp new file mode 100644 index 0000000..fa1f7d1 --- /dev/null +++ b/hbase-server/src/main/resources/hbase-webapps/master/processRS.jsp @@ -0,0 +1,230 @@ +<%-- +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--%> +<%@ page contentType="text/html;charset=UTF-8" + import="java.util.Date" + import="java.util.List" + import="org.apache.hadoop.hbase.HBaseConfiguration" + import="static org.apache.commons.lang.StringEscapeUtils.escapeXml" + import="javax.management.ObjectName" + import="java.lang.management.ManagementFactory" + import="java.lang.management.MemoryPoolMXBean" + import="java.lang.management.RuntimeMXBean" + import="java.lang.management.GarbageCollectorMXBean" + import="org.apache.hadoop.hbase.util.JSONMetricUtil" + import="org.apache.hadoop.hbase.procedure2.util.StringUtils" + import="org.codehaus.jackson.JsonNode" +%> +<% +RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); +ObjectName jvmMetrics = new ObjectName("Hadoop:service=HBase,name=JvmMetrics"); +ObjectName rsMetrics = new ObjectName("Hadoop:service=HBase,name=RegionServer,sub=Server"); + +// There is always two of GC collectors +List<GarbageCollectorMXBean> gcBeans = JSONMetricUtil.getGcCollectorBeans(); +GarbageCollectorMXBean collector1 = null; +GarbageCollectorMXBean collector2 = null; +try { +collector1 = gcBeans.get(0); +collector2 = gcBeans.get(1); +} catch(IndexOutOfBoundsException e) {} +List<MemoryPoolMXBean> mPools = JSONMetricUtil.getMemoryPools(); +%> +<!--[if IE]> +<!DOCTYPE html> +<![endif]--> +<?xml version="1.0" encoding="UTF-8" ?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta charset="utf-8"> + <title>Process info for PID: <%= JSONMetricUtil.getProcessPID() %></title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content=""> + + <link href="/static/css/bootstrap.min.css" rel="stylesheet"> + <link href="/static/css/bootstrap-theme.min.css" rel="stylesheet"> + <link href="/static/css/hbase.css" rel="stylesheet"> +</head> +<body> +<div class="navbar navbar-fixed-top navbar-default"> + <div class="container-fluid"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="/rs-status"><img src="/static/hbase_logo_small.png" alt="HBase Logo"/></a> + </div> + <div class="collapse navbar-collapse"> + <ul class="nav navbar-nav"> + <li><a href="/rs-status">Home</a></li> + <li><a href="/processRS.jsp">Process Metrics</a></li> + <li><a href="/logs/">Local Logs</a></li> + <li><a href="/dump">Debug Dump</a></li> + <li><a href="/jmx">Metrics Dump</a></li> + <% if (HBaseConfiguration.isShowConfInServlet()) { %> + <li><a href="/conf">HBase Configuration</a></li> + <% } %> + </ul> + </div><!--/.nav-collapse --> + </div> +</div> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h1><%= JSONMetricUtil.getCommmand().split(" ")[0] %></h1> + </div> + </div> + <table class="table table-striped" width="90%" > + <tr> + <th>Started</th> + <th>Uptime</th> + <th>PID</th> + <th>JvmPauseMonitor Count </th> + <th>Owner</th> + </tr> + <tr> + <tr> + <td><%= new Date(runtimeBean.getStartTime()) %></a></td> + <td><%= StringUtils.humanTimeDiff(runtimeBean.getUptime()) %></a></td> + <td><%= JSONMetricUtil.getProcessPID() %></a></td> + <td><%= (long)JSONMetricUtil.getValueFromMBean(rsMetrics, "pauseWarnThresholdExceeded") + + (long)JSONMetricUtil.getValueFromMBean(rsMetrics, "pauseInfoThresholdExceeded") %></a></td> + <td><%= runtimeBean.getSystemProperties().get("user.name") %></a></td> + </tr> + </table> +</div> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h2>Threads</h2> + </div> + </div> + <table class="table table-striped" width="90%" > + <tr> + <th>ThreadsNew</th> + <th>ThreadsRunable</th> + <th>ThreadsBlocked</th> + <th>ThreadsWaiting</th> + <th>ThreadsTimeWaiting</th> + <th>ThreadsTerminated</th> + </tr> + <tr> + <tr> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsNew") %></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsRunnable")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsBlocked")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsWaiting")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsTimedWaiting")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsTerminated")%></a></td> + </tr> + </table> +</div> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h2>GC Collectors</h2> + </div> + </div> + <% if (gcBeans.size() == 2) { %> +<div class="tabbable"> + <ul class="nav nav-pills"> + <li class="active"> + <a href="#tab_gc1" data-toggle="tab"><%=collector1.getName() %></a> + </li> + <li class=""> + <a href="#tab_gc2" data-toggle="tab"><%=collector2.getName() %></a> + </li> + </ul> + <div class="tab-content" style="padding-bottom: 9px; border-bottom: 1px solid #ddd;"> + <div class="tab-pane active" id="tab_gc1"> + <table class="table table-striped"> + <tr> + <th>Collection Count</th> + <th>Collection Time</th> + <th>Last duration</th> + </tr> + <tr> + <td> <%= collector1.getCollectionCount() %></td> + <td> <%= StringUtils.humanTimeDiff(collector1.getCollectionTime()) %> </td> + <td> <%= StringUtils.humanTimeDiff(JSONMetricUtil.getLastGcDuration( + collector1.getObjectName())) %></td> + </tr> + </table> + </div> + <div class="tab-pane" id="tab_gc2"> + <table class="table table-striped"> + <tr> + <th>Collection Count</th> + <th>Collection Time</th> + <th>Last duration</th> + </tr> + <tr> + <td> <%= collector2.getCollectionCount() %></td> + <td> <%= StringUtils.humanTimeDiff(collector2.getCollectionTime()) %> </td> + <td> <%= StringUtils.humanTimeDiff(JSONMetricUtil.getLastGcDuration( + collector2.getObjectName())) %></td> + </tr> + </table> + </div> + </div> + </div> + <%} else { %> + <p> Can not display GC Collector stats.</p> + <%} %> + Total GC Collection time: <%= StringUtils.humanTimeDiff(collector1.getCollectionTime() + + collector2.getCollectionTime())%> +</div> +<% for(MemoryPoolMXBean mp:mPools) { +if(mp.getName().contains("Cache")) continue;%> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h2><%= mp.getName() %></h2> + </div> + </div> + <table class="table table-striped" width="90%" > + <tr> + <th>Commited</th> + <th>Init</th> + <th>Max</th> + <th>Used</th> + <th>Utilization [%]</th> + </tr> + <tr> + <tr> + <td><%= StringUtils.humanSize(mp.getUsage().getCommitted()) %></a></td> + <td><%= StringUtils.humanSize(mp.getUsage().getInit())%></a></td> + <td><%= StringUtils.humanSize(mp.getUsage().getMax())%></a></td> + <td><%= StringUtils.humanSize(mp.getUsage().getUsed())%></a></td> + <td><%= JSONMetricUtil.calcPercentage(mp.getUsage().getUsed(), + mp.getUsage().getCommitted()) %></a></td> + </tr> + </table> +</div> +<% } %> + +<script src="/static/js/jquery.min.js" type="text/javascript"></script> +<script src="/static/js/bootstrap.min.js" type="text/javascript"></script> +<script src="/static/js/tab.js" type="text/javascript"></script> + +</body> +</html> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/resources/hbase-webapps/master/snapshot.jsp ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/resources/hbase-webapps/master/snapshot.jsp b/hbase-server/src/main/resources/hbase-webapps/master/snapshot.jsp index ad3ede5..a6ec23d 100644 --- a/hbase-server/src/main/resources/hbase-webapps/master/snapshot.jsp +++ b/hbase-server/src/main/resources/hbase-webapps/master/snapshot.jsp @@ -97,6 +97,7 @@ <li><a href="/master-status">Home</a></li> <li><a href="/tablesDetailed.jsp">Table Details</a></li> <li><a href="/procedures.jsp">Procedures & Locks</a></li> + <li><a href="/processMaster.jsp">Process Metrics</a></li> <li><a href="/logs/">Local Logs</a></li> <li><a href="/logLevel">Log Level</a></li> <li><a href="/dump">Debug Dump</a></li> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/resources/hbase-webapps/master/table.jsp ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/resources/hbase-webapps/master/table.jsp b/hbase-server/src/main/resources/hbase-webapps/master/table.jsp index fd656c6..fbf26d8 100644 --- a/hbase-server/src/main/resources/hbase-webapps/master/table.jsp +++ b/hbase-server/src/main/resources/hbase-webapps/master/table.jsp @@ -164,6 +164,7 @@ <li><a href="/master-status">Home</a></li> <li><a href="/tablesDetailed.jsp">Table Details</a></li> <li><a href="/procedures.jsp">Procedures & Locks</a></li> + <li><a href="/processMaster.jsp">Process Metrics</a></li> <li><a href="/logs/">Local Logs</a></li> <li><a href="/logLevel">Log Level</a></li> <li><a href="/dump">Debug Dump</a></li> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/resources/hbase-webapps/master/tablesDetailed.jsp ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/resources/hbase-webapps/master/tablesDetailed.jsp b/hbase-server/src/main/resources/hbase-webapps/master/tablesDetailed.jsp index e6bca57..eaa8c8f 100644 --- a/hbase-server/src/main/resources/hbase-webapps/master/tablesDetailed.jsp +++ b/hbase-server/src/main/resources/hbase-webapps/master/tablesDetailed.jsp @@ -67,6 +67,7 @@ <%if (master.isActiveMaster()) { %> <li><a href="/procedures.jsp">Procedures & Locks</a></li> <% } %> + <li><a href="/processMaster.jsp">Process Metrics</a></li> <li><a href="/logs/">Local Logs</a></li> <li><a href="/logLevel">Log Level</a></li> <li><a href="/dump">Debug Dump</a></li> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/resources/hbase-webapps/master/zk.jsp ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/resources/hbase-webapps/master/zk.jsp b/hbase-server/src/main/resources/hbase-webapps/master/zk.jsp index a2e6733..d08a2c4 100644 --- a/hbase-server/src/main/resources/hbase-webapps/master/zk.jsp +++ b/hbase-server/src/main/resources/hbase-webapps/master/zk.jsp @@ -61,6 +61,7 @@ <li><a href="/master-status">Home</a></li> <li><a href="/tablesDetailed.jsp">Table Details</a></li> <li><a href="/procedures.jsp">Procedures & Locks</a></li> + <li><a href="/processMaster.jsp">Process Metrics</a></li> <li><a href="/logs/">Local Logs</a></li> <li><a href="/logLevel">Log Level</a></li> <li><a href="/dump">Debug Dump</a></li> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/resources/hbase-webapps/regionserver/processRS.jsp ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/processRS.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/processRS.jsp new file mode 100644 index 0000000..fa1f7d1 --- /dev/null +++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/processRS.jsp @@ -0,0 +1,230 @@ +<%-- +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--%> +<%@ page contentType="text/html;charset=UTF-8" + import="java.util.Date" + import="java.util.List" + import="org.apache.hadoop.hbase.HBaseConfiguration" + import="static org.apache.commons.lang.StringEscapeUtils.escapeXml" + import="javax.management.ObjectName" + import="java.lang.management.ManagementFactory" + import="java.lang.management.MemoryPoolMXBean" + import="java.lang.management.RuntimeMXBean" + import="java.lang.management.GarbageCollectorMXBean" + import="org.apache.hadoop.hbase.util.JSONMetricUtil" + import="org.apache.hadoop.hbase.procedure2.util.StringUtils" + import="org.codehaus.jackson.JsonNode" +%> +<% +RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); +ObjectName jvmMetrics = new ObjectName("Hadoop:service=HBase,name=JvmMetrics"); +ObjectName rsMetrics = new ObjectName("Hadoop:service=HBase,name=RegionServer,sub=Server"); + +// There is always two of GC collectors +List<GarbageCollectorMXBean> gcBeans = JSONMetricUtil.getGcCollectorBeans(); +GarbageCollectorMXBean collector1 = null; +GarbageCollectorMXBean collector2 = null; +try { +collector1 = gcBeans.get(0); +collector2 = gcBeans.get(1); +} catch(IndexOutOfBoundsException e) {} +List<MemoryPoolMXBean> mPools = JSONMetricUtil.getMemoryPools(); +%> +<!--[if IE]> +<!DOCTYPE html> +<![endif]--> +<?xml version="1.0" encoding="UTF-8" ?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta charset="utf-8"> + <title>Process info for PID: <%= JSONMetricUtil.getProcessPID() %></title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content=""> + + <link href="/static/css/bootstrap.min.css" rel="stylesheet"> + <link href="/static/css/bootstrap-theme.min.css" rel="stylesheet"> + <link href="/static/css/hbase.css" rel="stylesheet"> +</head> +<body> +<div class="navbar navbar-fixed-top navbar-default"> + <div class="container-fluid"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="/rs-status"><img src="/static/hbase_logo_small.png" alt="HBase Logo"/></a> + </div> + <div class="collapse navbar-collapse"> + <ul class="nav navbar-nav"> + <li><a href="/rs-status">Home</a></li> + <li><a href="/processRS.jsp">Process Metrics</a></li> + <li><a href="/logs/">Local Logs</a></li> + <li><a href="/dump">Debug Dump</a></li> + <li><a href="/jmx">Metrics Dump</a></li> + <% if (HBaseConfiguration.isShowConfInServlet()) { %> + <li><a href="/conf">HBase Configuration</a></li> + <% } %> + </ul> + </div><!--/.nav-collapse --> + </div> +</div> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h1><%= JSONMetricUtil.getCommmand().split(" ")[0] %></h1> + </div> + </div> + <table class="table table-striped" width="90%" > + <tr> + <th>Started</th> + <th>Uptime</th> + <th>PID</th> + <th>JvmPauseMonitor Count </th> + <th>Owner</th> + </tr> + <tr> + <tr> + <td><%= new Date(runtimeBean.getStartTime()) %></a></td> + <td><%= StringUtils.humanTimeDiff(runtimeBean.getUptime()) %></a></td> + <td><%= JSONMetricUtil.getProcessPID() %></a></td> + <td><%= (long)JSONMetricUtil.getValueFromMBean(rsMetrics, "pauseWarnThresholdExceeded") + + (long)JSONMetricUtil.getValueFromMBean(rsMetrics, "pauseInfoThresholdExceeded") %></a></td> + <td><%= runtimeBean.getSystemProperties().get("user.name") %></a></td> + </tr> + </table> +</div> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h2>Threads</h2> + </div> + </div> + <table class="table table-striped" width="90%" > + <tr> + <th>ThreadsNew</th> + <th>ThreadsRunable</th> + <th>ThreadsBlocked</th> + <th>ThreadsWaiting</th> + <th>ThreadsTimeWaiting</th> + <th>ThreadsTerminated</th> + </tr> + <tr> + <tr> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsNew") %></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsRunnable")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsBlocked")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsWaiting")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsTimedWaiting")%></a></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsTerminated")%></a></td> + </tr> + </table> +</div> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h2>GC Collectors</h2> + </div> + </div> + <% if (gcBeans.size() == 2) { %> +<div class="tabbable"> + <ul class="nav nav-pills"> + <li class="active"> + <a href="#tab_gc1" data-toggle="tab"><%=collector1.getName() %></a> + </li> + <li class=""> + <a href="#tab_gc2" data-toggle="tab"><%=collector2.getName() %></a> + </li> + </ul> + <div class="tab-content" style="padding-bottom: 9px; border-bottom: 1px solid #ddd;"> + <div class="tab-pane active" id="tab_gc1"> + <table class="table table-striped"> + <tr> + <th>Collection Count</th> + <th>Collection Time</th> + <th>Last duration</th> + </tr> + <tr> + <td> <%= collector1.getCollectionCount() %></td> + <td> <%= StringUtils.humanTimeDiff(collector1.getCollectionTime()) %> </td> + <td> <%= StringUtils.humanTimeDiff(JSONMetricUtil.getLastGcDuration( + collector1.getObjectName())) %></td> + </tr> + </table> + </div> + <div class="tab-pane" id="tab_gc2"> + <table class="table table-striped"> + <tr> + <th>Collection Count</th> + <th>Collection Time</th> + <th>Last duration</th> + </tr> + <tr> + <td> <%= collector2.getCollectionCount() %></td> + <td> <%= StringUtils.humanTimeDiff(collector2.getCollectionTime()) %> </td> + <td> <%= StringUtils.humanTimeDiff(JSONMetricUtil.getLastGcDuration( + collector2.getObjectName())) %></td> + </tr> + </table> + </div> + </div> + </div> + <%} else { %> + <p> Can not display GC Collector stats.</p> + <%} %> + Total GC Collection time: <%= StringUtils.humanTimeDiff(collector1.getCollectionTime() + + collector2.getCollectionTime())%> +</div> +<% for(MemoryPoolMXBean mp:mPools) { +if(mp.getName().contains("Cache")) continue;%> +<div class="container-fluid content"> + <div class="row"> + <div class="page-header"> + <h2><%= mp.getName() %></h2> + </div> + </div> + <table class="table table-striped" width="90%" > + <tr> + <th>Commited</th> + <th>Init</th> + <th>Max</th> + <th>Used</th> + <th>Utilization [%]</th> + </tr> + <tr> + <tr> + <td><%= StringUtils.humanSize(mp.getUsage().getCommitted()) %></a></td> + <td><%= StringUtils.humanSize(mp.getUsage().getInit())%></a></td> + <td><%= StringUtils.humanSize(mp.getUsage().getMax())%></a></td> + <td><%= StringUtils.humanSize(mp.getUsage().getUsed())%></a></td> + <td><%= JSONMetricUtil.calcPercentage(mp.getUsage().getUsed(), + mp.getUsage().getCommitted()) %></a></td> + </tr> + </table> +</div> +<% } %> + +<script src="/static/js/jquery.min.js" type="text/javascript"></script> +<script src="/static/js/bootstrap.min.js" type="text/javascript"></script> +<script src="/static/js/tab.js" type="text/javascript"></script> + +</body> +</html> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/main/resources/hbase-webapps/regionserver/region.jsp ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/region.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/region.jsp index 874ac43..6a7fe7b 100644 --- a/hbase-server/src/main/resources/hbase-webapps/regionserver/region.jsp +++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/region.jsp @@ -73,6 +73,7 @@ <div class="collapse navbar-collapse"> <ul class="nav navbar-nav"> <li class="active"><a href="/rs-status">Home</a></li> + <li><a href="/processRS.jsp">Process Metrics</a></li> <li><a href="/logs/">Local Logs</a></li> <li><a href="/logLevel">Log Level</a></li> <li><a href="/dump">Debug Dump</a></li> http://git-wip-us.apache.org/repos/asf/hbase/blob/193a9803/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestJSONMetricUtil.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestJSONMetricUtil.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestJSONMetricUtil.java new file mode 100644 index 0000000..30da26a --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestJSONMetricUtil.java @@ -0,0 +1,106 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.util; + +import java.io.IOException; +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +import java.util.Hashtable; +import java.util.List; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.testclassification.MiscTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.JsonProcessingException; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category({MiscTests.class, SmallTests.class}) +public class TestJSONMetricUtil { + + private static final Log LOG = LogFactory.getLog(TestJSONMetricUtil.class); + + @Test + public void testBuildHashtable() { + String[] keys = {"type", "name"}; + String[] emptyKey = {}; + String[] values = {"MemoryPool", "Par Eden Space"}; + String[] values2 = {"MemoryPool", "Par Eden Space", "Test"}; + String[] emptyValue = {}; + Hashtable<String, String> properties = JSONMetricUtil.buldKeyValueTable(keys, values); + Hashtable<String, String> nullObject = JSONMetricUtil.buldKeyValueTable(keys, values2); + Hashtable<String, String> nullObject1 = JSONMetricUtil.buldKeyValueTable(keys, emptyValue); + Hashtable<String, String> nullObject2 = JSONMetricUtil.buldKeyValueTable(emptyKey, values2); + Hashtable<String, String> nullObject3 = JSONMetricUtil.buldKeyValueTable(emptyKey, emptyValue); + assertEquals(properties.get("type"), values[0]); + assertEquals(properties.get("name"), values[1]); + assertEquals(nullObject, null); + assertEquals(nullObject1, null); + assertEquals(nullObject2, null); + assertEquals(nullObject3, null); + } + + @Test + public void testSearchJson() throws JsonProcessingException, IOException { + String jsonString = "{\"test\":[{\"data1\":100,\"data2\":\"hello\",\"data3\": [1 , 2 , 3]}, " + + "{\"data4\":0}]}"; + JsonNode node = JSONMetricUtil.mappStringToJsonNode(jsonString); + JsonNode r1 = JSONMetricUtil.searchJson(node, "data1"); + JsonNode r2 = JSONMetricUtil.searchJson(node, "data2"); + JsonNode r3 = JSONMetricUtil.searchJson(node, "data3"); + JsonNode r4 = JSONMetricUtil.searchJson(node, "data4"); + assertEquals(r1.getIntValue(), 100); + assertEquals(r2.getTextValue(), "hello"); + assertEquals(r3.get(0).getIntValue(), 1); + assertEquals(r4.getIntValue(), 0); + } + + @Test + public void testBuildObjectName() throws MalformedObjectNameException { + String[] keys = {"type", "name"}; + String[] values = {"MemoryPool", "Par Eden Space"}; + Hashtable<String, String> properties = JSONMetricUtil.buldKeyValueTable(keys, values); + ObjectName testObject = JSONMetricUtil.buildObjectName(JSONMetricUtil.JAVA_LANG_DOMAIN, + properties); + assertEquals(testObject.getDomain(), JSONMetricUtil.JAVA_LANG_DOMAIN); + assertEquals(testObject.getKeyPropertyList(), properties); + } + + @Test + public void testGetLastGCInfo() { + List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); + for(GarbageCollectorMXBean bean:gcBeans) { + ObjectName on = bean.getObjectName(); + Object value = JSONMetricUtil.getValueFromMBean(on, "LastGcInfo"); + LOG.info("Collector Info: "+ value); + if (value != null && value instanceof CompositeData) { + CompositeData cds = (CompositeData)value; + assertNotNull(cds.get("duration")); + } + } + } +}
