This is an automated email from the ASF dual-hosted git repository. nihaljain pushed a commit to branch branch-3 in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-3 by this push: new 5129cbe3a6a HBASE-27814 Add support for dump and process metrics servlet in REST InfoServer (#5215) 5129cbe3a6a is described below commit 5129cbe3a6aa90e8e5112b65d007893bcec126a8 Author: Nihal Jain <nihalj...@apache.org> AuthorDate: Sun Jan 14 11:59:26 2024 +0530 HBASE-27814 Add support for dump and process metrics servlet in REST InfoServer (#5215) Other changes: - Ensure info server stops during stop() - Extract header and footer. This would fix the log level page layout for rest web UI (See HBASE-20693) - Add hostname in the landing page instead of just port similar to other web UIs Signed-off-by: Nick Dimiduk <ndimi...@apache.org> (cherry picked from commit a683fcfbe8c5c84e58fa8670f4414f9d01ff43ed) --- .../apache/hadoop/hbase/rest/RESTDumpServlet.java | 80 +++++++++ .../org/apache/hadoop/hbase/rest/RESTServer.java | 39 ++++- .../main/resources/hbase-webapps/rest/footer.jsp | 32 ++++ .../main/resources/hbase-webapps/rest/header.jsp | 74 +++++++++ .../resources/hbase-webapps/rest/processRest.jsp | 184 +++++++++++++++++++++ .../src/main/resources/hbase-webapps/rest/rest.jsp | 80 ++------- 6 files changed, 422 insertions(+), 67 deletions(-) diff --git a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTDumpServlet.java b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTDumpServlet.java new file mode 100644 index 00000000000..8bb306f7829 --- /dev/null +++ b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTDumpServlet.java @@ -0,0 +1,80 @@ +/* + * 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.rest; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.Date; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.http.HttpServer; +import org.apache.hadoop.hbase.monitoring.StateDumpServlet; +import org.apache.hadoop.hbase.util.LogMonitoring; +import org.apache.hadoop.hbase.util.Threads; +import org.apache.yetus.audience.InterfaceAudience; + +@InterfaceAudience.Private +public class RESTDumpServlet extends StateDumpServlet { + private static final long serialVersionUID = 1L; + private static final String LINE = "==========================================================="; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(), request, response)) { + return; + } + + RESTServer restServer = (RESTServer) getServletContext().getAttribute(RESTServer.REST_SERVER); + assert restServer != null : "No REST Server in context!"; + + response.setContentType("text/plain"); + OutputStream os = response.getOutputStream(); + try (PrintWriter out = new PrintWriter(os)) { + + out.println("REST Server status for " + restServer.getServerName() + " as of " + new Date()); + + out.println("\n\nVersion Info:"); + out.println(LINE); + dumpVersionInfo(out); + + out.println("\n\nStacks:"); + out.println(LINE); + out.flush(); + PrintStream ps = new PrintStream(response.getOutputStream(), false, "UTF-8"); + Threads.printThreadInfo(ps, ""); + ps.flush(); + + out.println("\n\nREST Server configuration:"); + out.println(LINE); + Configuration conf = restServer.conf; + out.flush(); + conf.writeXml(os); + os.flush(); + + out.println("\n\nLogs"); + out.println(LINE); + long tailKb = getTailKbParam(request); + LogMonitoring.dumpTailOfLogs(out, tailKb); + + out.flush(); + } + } +} diff --git a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java index 886c81dc668..42c00480526 100644 --- a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java +++ b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java @@ -18,6 +18,7 @@ package org.apache.hadoop.hbase.rest; import java.lang.management.ManagementFactory; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; @@ -29,6 +30,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseInterfaceAudience; +import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.http.ClickjackingPreventionFilter; import org.apache.hadoop.hbase.http.HttpServerUtil; import org.apache.hadoop.hbase.http.InfoServer; @@ -83,6 +85,7 @@ import org.apache.hbase.thirdparty.org.glassfish.jersey.servlet.ServletContainer @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS) public class RESTServer implements Constants { static Logger LOG = LoggerFactory.getLogger("RESTServer"); + public static final String REST_SERVER = "rest"; static final String REST_CSRF_ENABLED_KEY = "hbase.rest.csrf.enabled"; static final boolean REST_CSRF_ENABLED_DEFAULT = false; @@ -112,6 +115,7 @@ public class RESTServer implements Constants { private final UserProvider userProvider; private Server server; private InfoServer infoServer; + private ServerName serverName; public RESTServer(Configuration conf) { RESTServer.conf = conf; @@ -163,8 +167,7 @@ public class RESTServer implements Constants { loginServerPrincipal(UserProvider userProvider, Configuration conf) throws Exception { Class<? extends ServletContainer> containerClass = ServletContainer.class; if (userProvider.isHadoopSecurityEnabled() && userProvider.isHBaseSecurityEnabled()) { - String machineName = Strings.domainNamePointerToHostName(DNS.getDefaultHost( - conf.get(REST_DNS_INTERFACE, "default"), conf.get(REST_DNS_NAMESERVER, "default"))); + String machineName = getHostName(conf); String keytabFilename = conf.get(REST_KEYTAB_FILE); Preconditions.checkArgument(keytabFilename != null && !keytabFilename.isEmpty(), REST_KEYTAB_FILE + " should be set if security is enabled"); @@ -402,9 +405,14 @@ public class RESTServer implements Constants { // Put up info server. int port = conf.getInt("hbase.rest.info.port", 8085); if (port >= 0) { - conf.setLong("startcode", EnvironmentEdgeManager.currentTime()); - String a = conf.get("hbase.rest.info.bindAddress", "0.0.0.0"); - this.infoServer = new InfoServer("rest", a, port, false, conf); + final long startCode = EnvironmentEdgeManager.currentTime(); + conf.setLong("startcode", startCode); + this.serverName = ServerName.valueOf(getHostName(conf), servicePort, startCode); + + String addr = conf.get("hbase.rest.info.bindAddress", "0.0.0.0"); + this.infoServer = new InfoServer(REST_SERVER, addr, port, false, conf); + this.infoServer.addPrivilegedServlet("dump", "/dump", RESTDumpServlet.class); + this.infoServer.setAttribute(REST_SERVER, this); this.infoServer.setAttribute("hbase.conf", conf); this.infoServer.start(); } @@ -412,6 +420,11 @@ public class RESTServer implements Constants { server.start(); } + private static String getHostName(Configuration conf) throws UnknownHostException { + return Strings.domainNamePointerToHostName(DNS.getDefaultHost( + conf.get(REST_DNS_INTERFACE, "default"), conf.get(REST_DNS_NAMESERVER, "default"))); + } + public synchronized void join() throws Exception { if (server == null) { throw new IllegalStateException("Server is not running"); @@ -419,7 +432,19 @@ public class RESTServer implements Constants { server.join(); } + private void stopInfoServer() { + if (this.infoServer != null) { + LOG.info("Stop info server"); + try { + this.infoServer.stop(); + } catch (Exception e) { + LOG.error("Failed to stop infoServer", e); + } + } + } + public synchronized void stop() throws Exception { + stopInfoServer(); if (server == null) { throw new IllegalStateException("Server is not running"); } @@ -443,6 +468,10 @@ public class RESTServer implements Constants { return infoServer.getPort(); } + public ServerName getServerName() { + return serverName; + } + public Configuration getConf() { return conf; } diff --git a/hbase-rest/src/main/resources/hbase-webapps/rest/footer.jsp b/hbase-rest/src/main/resources/hbase-webapps/rest/footer.jsp new file mode 100644 index 00000000000..a642ac36eff --- /dev/null +++ b/hbase-rest/src/main/resources/hbase-webapps/rest/footer.jsp @@ -0,0 +1,32 @@ +<%-- +/** +* 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. +*/ +--%> + + <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> + <script type="text/javascript"> + $(document).ready(function() { + $('div.navbar li.active').removeClass('active'); + $('a[href="' + location.pathname + '"]').closest('li').addClass('active'); + }); + </script> +</body> +</html> + diff --git a/hbase-rest/src/main/resources/hbase-webapps/rest/header.jsp b/hbase-rest/src/main/resources/hbase-webapps/rest/header.jsp new file mode 100644 index 00000000000..67f7656de59 --- /dev/null +++ b/hbase-rest/src/main/resources/hbase-webapps/rest/header.jsp @@ -0,0 +1,74 @@ +<%-- +/** +* 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="org.apache.hadoop.hbase.HBaseConfiguration"%> + +<!DOCTYPE html> +<?xml version="1.0" encoding="UTF-8" ?> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title><%= request.getParameter("pageTitle")%></title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" 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="/rest.jsp"><img src="/static/hbase_logo_small.png" alt="HBase Logo"/></a> + </div> + <div class="collapse navbar-collapse"> + <ul class="nav navbar-nav"> + <li class="active"><a href="/rest.jsp">Home</a></li> + <li><a href="/logs/">Local logs</a></li> + <li><a href="/processRest.jsp">Process Metrics</a></li> + <li><a href="/logLevel">Log Level</a></li> + <li><a href="/dump">Debug Dump</a></li> + <li class="nav-item dropdown"> + <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + Metrics <span class="caret"></span> + </a> + <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> + <li><a target="_blank" href="/jmx">JMX</a></li> + <li><a target="_blank" href="/jmx?description=true">JMX with description</a></li> + <li><a target="_blank" href="/prometheus">Prometheus</a></li> + <li><a target="_blank" href="/prometheus?description=true">Prometheus with description</a></li> + </ul> + </li> + <li><a href="/prof">Profiler</a></li> + <% if (HBaseConfiguration.isShowConfInServlet()) { %> + <li><a href="/conf">HBase Configuration</a></li> + <% } %> + </ul> + </div><!--/.nav-collapse --> + </div> +</div> + diff --git a/hbase-rest/src/main/resources/hbase-webapps/rest/processRest.jsp b/hbase-rest/src/main/resources/hbase-webapps/rest/processRest.jsp new file mode 100644 index 00000000000..2b2d35fbfb3 --- /dev/null +++ b/hbase-rest/src/main/resources/hbase-webapps/rest/processRest.jsp @@ -0,0 +1,184 @@ +<%-- +/** + * 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="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.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix" +%> + +<% +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(); +pageContext.setAttribute("pageTitle", "Process info for PID: " + JSONMetricUtil.getProcessPID()); +%> + +<jsp:include page="header.jsp"> + <jsp:param name="pageTitle" value="${pageTitle}"/> +</jsp:include> + +<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()) %></td> + <td><%= StringUtils.humanTimeDiff(runtimeBean.getUptime()) %></td> + <td><%= JSONMetricUtil.getProcessPID() %></td> + <td><%= runtimeBean.getSystemProperties().get("user.name") %></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") %></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsRunnable")%></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsBlocked")%></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsWaiting")%></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsTimedWaiting")%></td> + <td><%= JSONMetricUtil.getValueFromMBean(jvmMetrics, "ThreadsTerminated")%></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><%= TraditionalBinaryPrefix.long2String(mp.getUsage().getCommitted(), "B", 1) %></td> + <td><%= TraditionalBinaryPrefix.long2String(mp.getUsage().getInit(), "B", 1) %></td> + <td><%= TraditionalBinaryPrefix.long2String(mp.getUsage().getMax(), "B", 1) %></td> + <td><%= TraditionalBinaryPrefix.long2String(mp.getUsage().getUsed(), "B", 1) %></td> + <td><%= JSONMetricUtil.calcPercentage(mp.getUsage().getUsed(), + mp.getUsage().getCommitted()) %></td> + </tr> + </table> +</div> +<% } %> + +<jsp:include page="footer.jsp" /> diff --git a/hbase-rest/src/main/resources/hbase-webapps/rest/rest.jsp b/hbase-rest/src/main/resources/hbase-webapps/rest/rest.jsp index df8f0838d6c..ce6725f283a 100644 --- a/hbase-rest/src/main/resources/hbase-webapps/rest/rest.jsp +++ b/hbase-rest/src/main/resources/hbase-webapps/rest/rest.jsp @@ -18,70 +18,29 @@ */ --%> <%@ page contentType="text/html;charset=UTF-8" - import="org.apache.hadoop.conf.Configuration" - import="org.apache.hadoop.hbase.HBaseConfiguration" - import="org.apache.hadoop.hbase.rest.model.VersionModel" - import="org.apache.hadoop.hbase.util.VersionInfo" - import="java.util.Date"%> + import="org.apache.hadoop.conf.Configuration" + import="org.apache.hadoop.hbase.rest.RESTServer" + import="org.apache.hadoop.hbase.rest.model.VersionModel" + import="org.apache.hadoop.hbase.util.VersionInfo" + import="java.util.Date"%> + <% -Configuration conf = (Configuration)getServletContext().getAttribute("hbase.conf"); -long startcode = conf.getLong("startcode", System.currentTimeMillis()); -String listenPort = conf.get("hbase.rest.port", "8080"); -%> -<!DOCTYPE html> -<?xml version="1.0" encoding="UTF-8" ?> -<html lang="en"> - <head> - <meta charset="utf-8"> - <title>HBase REST Server: <%= listenPort %></title> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <meta name="description" content=""> + Configuration conf = (Configuration) getServletContext().getAttribute("hbase.conf"); + long startcode = conf.getLong("startcode", System.currentTimeMillis()); - <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> + final RESTServer restServer = (RESTServer) getServletContext().getAttribute(RESTServer.REST_SERVER); + final String hostName = restServer.getServerName().getHostname(); + pageContext.setAttribute("pageTitle", "HBase REST Server" + hostName); +%> - <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="/rest.jsp"><img src="/static/hbase_logo_small.png" alt="HBase Logo"/></a> - </div> - <div class="collapse navbar-collapse"> - <ul class="nav navbar-nav"> - <li class="active"><a href="/rest.jsp">Home</a></li> - <li><a href="/logs/">Local logs</a></li> - <li><a href="/logLevel">Log Level</a></li> - <li class="nav-item dropdown"> - <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - Metrics <span class="caret"></span> - </a> - <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> - <li><a target="_blank" href="/jmx">JMX</a></li> - <li><a target="_blank" href="/jmx?description=true">JMX with description</a></li> - <li><a target="_blank" href="/prometheus">Prometheus</a></li> - <li><a target="_blank" href="/prometheus?description=true">Prometheus with description</a></li> - </ul> - </li> - <li><a href="/prof">Profiler</a></li> - <% if (HBaseConfiguration.isShowConfInServlet()) { %> - <li><a href="/conf">HBase Configuration</a></li> - <% } %> - </ul> - </div><!--/.nav-collapse --> - </div> - </div> +<jsp:include page="header.jsp"> + <jsp:param name="pageTitle" value="${pageTitle}"/> +</jsp:include> <div class="container-fluid content"> <div class="row inner_header"> <div class="page-header"> - <h1>RESTServer <small><%= listenPort %></small></h1> + <h1>RESTServer <small><%= hostName %></small></h1> </div> </div> <div class="row"> @@ -124,9 +83,6 @@ String listenPort = conf.get("hbase.rest.port", "8080"); </section> </div> </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> + +<jsp:include page="footer.jsp" />