Skip to content

Commit a683fcf

Browse files
authored
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 <ndimiduk@apache.org>
1 parent e3a0174 commit a683fcf

File tree

6 files changed

+422
-67
lines changed

6 files changed

+422
-67
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.rest;
19+
20+
import java.io.IOException;
21+
import java.io.OutputStream;
22+
import java.io.PrintStream;
23+
import java.io.PrintWriter;
24+
import java.util.Date;
25+
import javax.servlet.http.HttpServletRequest;
26+
import javax.servlet.http.HttpServletResponse;
27+
import org.apache.hadoop.conf.Configuration;
28+
import org.apache.hadoop.hbase.http.HttpServer;
29+
import org.apache.hadoop.hbase.monitoring.StateDumpServlet;
30+
import org.apache.hadoop.hbase.util.LogMonitoring;
31+
import org.apache.hadoop.hbase.util.Threads;
32+
import org.apache.yetus.audience.InterfaceAudience;
33+
34+
@InterfaceAudience.Private
35+
public class RESTDumpServlet extends StateDumpServlet {
36+
private static final long serialVersionUID = 1L;
37+
private static final String LINE = "===========================================================";
38+
39+
@Override
40+
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
41+
if (!HttpServer.isInstrumentationAccessAllowed(getServletContext(), request, response)) {
42+
return;
43+
}
44+
45+
RESTServer restServer = (RESTServer) getServletContext().getAttribute(RESTServer.REST_SERVER);
46+
assert restServer != null : "No REST Server in context!";
47+
48+
response.setContentType("text/plain");
49+
OutputStream os = response.getOutputStream();
50+
try (PrintWriter out = new PrintWriter(os)) {
51+
52+
out.println("REST Server status for " + restServer.getServerName() + " as of " + new Date());
53+
54+
out.println("\n\nVersion Info:");
55+
out.println(LINE);
56+
dumpVersionInfo(out);
57+
58+
out.println("\n\nStacks:");
59+
out.println(LINE);
60+
out.flush();
61+
PrintStream ps = new PrintStream(response.getOutputStream(), false, "UTF-8");
62+
Threads.printThreadInfo(ps, "");
63+
ps.flush();
64+
65+
out.println("\n\nREST Server configuration:");
66+
out.println(LINE);
67+
Configuration conf = restServer.conf;
68+
out.flush();
69+
conf.writeXml(os);
70+
os.flush();
71+
72+
out.println("\n\nLogs");
73+
out.println(LINE);
74+
long tailKb = getTailKbParam(request);
75+
LogMonitoring.dumpTailOfLogs(out, tailKb);
76+
77+
out.flush();
78+
}
79+
}
80+
}

hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.apache.hadoop.hbase.rest;
1919

2020
import java.lang.management.ManagementFactory;
21+
import java.net.UnknownHostException;
2122
import java.util.ArrayList;
2223
import java.util.EnumSet;
2324
import java.util.List;
@@ -29,6 +30,7 @@
2930
import org.apache.hadoop.conf.Configuration;
3031
import org.apache.hadoop.hbase.HBaseConfiguration;
3132
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
33+
import org.apache.hadoop.hbase.ServerName;
3234
import org.apache.hadoop.hbase.http.ClickjackingPreventionFilter;
3335
import org.apache.hadoop.hbase.http.HttpServerUtil;
3436
import org.apache.hadoop.hbase.http.InfoServer;
@@ -83,6 +85,7 @@
8385
@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
8486
public class RESTServer implements Constants {
8587
static Logger LOG = LoggerFactory.getLogger("RESTServer");
88+
public static final String REST_SERVER = "rest";
8689

8790
static final String REST_CSRF_ENABLED_KEY = "hbase.rest.csrf.enabled";
8891
static final boolean REST_CSRF_ENABLED_DEFAULT = false;
@@ -112,6 +115,7 @@ public class RESTServer implements Constants {
112115
private final UserProvider userProvider;
113116
private Server server;
114117
private InfoServer infoServer;
118+
private ServerName serverName;
115119

116120
public RESTServer(Configuration conf) {
117121
RESTServer.conf = conf;
@@ -163,8 +167,7 @@ private void addSecurityHeadersFilter(ServletContextHandler ctxHandler, Configur
163167
loginServerPrincipal(UserProvider userProvider, Configuration conf) throws Exception {
164168
Class<? extends ServletContainer> containerClass = ServletContainer.class;
165169
if (userProvider.isHadoopSecurityEnabled() && userProvider.isHBaseSecurityEnabled()) {
166-
String machineName = Strings.domainNamePointerToHostName(DNS.getDefaultHost(
167-
conf.get(REST_DNS_INTERFACE, "default"), conf.get(REST_DNS_NAMESERVER, "default")));
170+
String machineName = getHostName(conf);
168171
String keytabFilename = conf.get(REST_KEYTAB_FILE);
169172
Preconditions.checkArgument(keytabFilename != null && !keytabFilename.isEmpty(),
170173
REST_KEYTAB_FILE + " should be set if security is enabled");
@@ -402,24 +405,46 @@ public synchronized void run() throws Exception {
402405
// Put up info server.
403406
int port = conf.getInt("hbase.rest.info.port", 8085);
404407
if (port >= 0) {
405-
conf.setLong("startcode", EnvironmentEdgeManager.currentTime());
406-
String a = conf.get("hbase.rest.info.bindAddress", "0.0.0.0");
407-
this.infoServer = new InfoServer("rest", a, port, false, conf);
408+
final long startCode = EnvironmentEdgeManager.currentTime();
409+
conf.setLong("startcode", startCode);
410+
this.serverName = ServerName.valueOf(getHostName(conf), servicePort, startCode);
411+
412+
String addr = conf.get("hbase.rest.info.bindAddress", "0.0.0.0");
413+
this.infoServer = new InfoServer(REST_SERVER, addr, port, false, conf);
414+
this.infoServer.addPrivilegedServlet("dump", "/dump", RESTDumpServlet.class);
415+
this.infoServer.setAttribute(REST_SERVER, this);
408416
this.infoServer.setAttribute("hbase.conf", conf);
409417
this.infoServer.start();
410418
}
411419
// start server
412420
server.start();
413421
}
414422

423+
private static String getHostName(Configuration conf) throws UnknownHostException {
424+
return Strings.domainNamePointerToHostName(DNS.getDefaultHost(
425+
conf.get(REST_DNS_INTERFACE, "default"), conf.get(REST_DNS_NAMESERVER, "default")));
426+
}
427+
415428
public synchronized void join() throws Exception {
416429
if (server == null) {
417430
throw new IllegalStateException("Server is not running");
418431
}
419432
server.join();
420433
}
421434

435+
private void stopInfoServer() {
436+
if (this.infoServer != null) {
437+
LOG.info("Stop info server");
438+
try {
439+
this.infoServer.stop();
440+
} catch (Exception e) {
441+
LOG.error("Failed to stop infoServer", e);
442+
}
443+
}
444+
}
445+
422446
public synchronized void stop() throws Exception {
447+
stopInfoServer();
423448
if (server == null) {
424449
throw new IllegalStateException("Server is not running");
425450
}
@@ -443,6 +468,10 @@ public synchronized int getInfoPort() {
443468
return infoServer.getPort();
444469
}
445470

471+
public ServerName getServerName() {
472+
return serverName;
473+
}
474+
446475
public Configuration getConf() {
447476
return conf;
448477
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<%--
2+
/**
3+
* Licensed to the Apache Software Foundation (ASF) under one
4+
* or more contributor license agreements. See the NOTICE file
5+
* distributed with this work for additional information
6+
* regarding copyright ownership. The ASF licenses this file
7+
* to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance
9+
* with the License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
--%>
20+
21+
<script src="/static/js/jquery.min.js" type="text/javascript"></script>
22+
<script src="/static/js/bootstrap.min.js" type="text/javascript"></script>
23+
<script src="/static/js/tab.js" type="text/javascript"></script>
24+
<script type="text/javascript">
25+
$(document).ready(function() {
26+
$('div.navbar li.active').removeClass('active');
27+
$('a[href="' + location.pathname + '"]').closest('li').addClass('active');
28+
});
29+
</script>
30+
</body>
31+
</html>
32+
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<%--
2+
/**
3+
* Licensed to the Apache Software Foundation (ASF) under one
4+
* or more contributor license agreements. See the NOTICE file
5+
* distributed with this work for additional information
6+
* regarding copyright ownership. The ASF licenses this file
7+
* to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance
9+
* with the License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
--%>
20+
<%@ page contentType="text/html;charset=UTF-8"
21+
import="org.apache.hadoop.hbase.HBaseConfiguration"%>
22+
23+
<!DOCTYPE html>
24+
<?xml version="1.0" encoding="UTF-8" ?>
25+
<html lang="en">
26+
<head>
27+
<meta charset="utf-8">
28+
<title><%= request.getParameter("pageTitle")%></title>
29+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
30+
<meta name="description" content="">
31+
32+
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
33+
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet">
34+
<link href="/static/css/hbase.css" rel="stylesheet">
35+
</head>
36+
37+
<body>
38+
<div class="navbar navbar-fixed-top navbar-default">
39+
<div class="container-fluid">
40+
<div class="navbar-header">
41+
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
42+
<span class="icon-bar"></span>
43+
<span class="icon-bar"></span>
44+
<span class="icon-bar"></span>
45+
</button>
46+
<a class="navbar-brand" href="/rest.jsp"><img src="/static/hbase_logo_small.png" alt="HBase Logo"/></a>
47+
</div>
48+
<div class="collapse navbar-collapse">
49+
<ul class="nav navbar-nav">
50+
<li class="active"><a href="/rest.jsp">Home</a></li>
51+
<li><a href="/logs/">Local logs</a></li>
52+
<li><a href="/processRest.jsp">Process Metrics</a></li>
53+
<li><a href="/logLevel">Log Level</a></li>
54+
<li><a href="/dump">Debug Dump</a></li>
55+
<li class="nav-item dropdown">
56+
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
57+
Metrics <span class="caret"></span>
58+
</a>
59+
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
60+
<li><a target="_blank" href="/jmx">JMX</a></li>
61+
<li><a target="_blank" href="/jmx?description=true">JMX with description</a></li>
62+
<li><a target="_blank" href="/prometheus">Prometheus</a></li>
63+
<li><a target="_blank" href="/prometheus?description=true">Prometheus with description</a></li>
64+
</ul>
65+
</li>
66+
<li><a href="/prof">Profiler</a></li>
67+
<% if (HBaseConfiguration.isShowConfInServlet()) { %>
68+
<li><a href="/conf">HBase Configuration</a></li>
69+
<% } %>
70+
</ul>
71+
</div><!--/.nav-collapse -->
72+
</div>
73+
</div>
74+

0 commit comments

Comments
 (0)