HTRACE-288. htraced: Add a user interface to view server version, metrics, and configuration (cmccabe)
diff --git a/htrace-htraced/go/src/org/apache/htrace/client/client.go b/htrace-htraced/go/src/org/apache/htrace/client/client.go
index dd8597d..fb46e62 100644
--- a/htrace-htraced/go/src/org/apache/htrace/client/client.go
+++ b/htrace-htraced/go/src/org/apache/htrace/client/client.go
@@ -52,13 +52,13 @@
hcr *hClient
}
-// Get the htraced server information.
-func (hcl *Client) GetServerInfo() (*common.ServerInfo, error) {
+// Get the htraced server version information.
+func (hcl *Client) GetServerVersion() (*common.ServerVersion, error) {
buf, _, err := hcl.makeGetRequest("server/info")
if err != nil {
return nil, err
}
- var info common.ServerInfo
+ var info common.ServerVersion
err = json.Unmarshal(buf, &info)
if err != nil {
return nil, errors.New(fmt.Sprintf("Error: error unmarshalling response "+
diff --git a/htrace-htraced/go/src/org/apache/htrace/common/rpc.go b/htrace-htraced/go/src/org/apache/htrace/common/rpc.go
index 5e57f08..f071e37 100644
--- a/htrace-htraced/go/src/org/apache/htrace/common/rpc.go
+++ b/htrace-htraced/go/src/org/apache/htrace/common/rpc.go
@@ -44,8 +44,8 @@
ClientDropped uint64 `json:",omitempty"`
}
-// Info returned by /server/info
-type ServerInfo struct {
+// Info returned by /server/version
+type ServerVersion struct {
// The server release version.
ReleaseVersion string
diff --git a/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go b/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
index 14b7f73..98b1646 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htrace/cmd.go
@@ -70,7 +70,7 @@
addr := app.Flag("addr", "Server address.").String()
verbose = *app.Flag("verbose", "Verbose.").Default("false").Bool()
version := app.Command("version", "Print the version of this program.")
- serverInfo := app.Command("serverInfo", "Print information retrieved from an htraced server.")
+ serverVersion := app.Command("serverVersion", "Print the version of the htraced server.")
serverStats := app.Command("serverStats", "Print statistics retrieved from the htraced server.")
serverStatsJson := serverStats.Flag("json", "Display statistics as raw JSON.").Default("false").Bool()
serverConf := app.Command("serverConf", "Print the server configuration retrieved from the htraced server.")
@@ -132,8 +132,8 @@
switch cmd {
case version.FullCommand():
os.Exit(printVersion())
- case serverInfo.FullCommand():
- os.Exit(printServerInfo(hcl))
+ case serverVersion.FullCommand():
+ os.Exit(printServerVersion(hcl))
case serverStats.FullCommand():
if *serverStatsJson {
os.Exit(printServerStatsJson(hcl))
@@ -187,13 +187,13 @@
}
// Print information retrieved from an htraced server via /server/info
-func printServerInfo(hcl *htrace.Client) int {
- info, err := hcl.GetServerInfo()
+func printServerVersion(hcl *htrace.Client) int {
+ ver, err := hcl.GetServerVersion()
if err != nil {
fmt.Println(err.Error())
return EXIT_FAILURE
}
- fmt.Printf("HTraced server version %s (%s)\n", info.ReleaseVersion, info.GitVersion)
+ fmt.Printf("HTraced server version %s (%s)\n", ver.ReleaseVersion, ver.GitVersion)
return EXIT_SUCCESS
}
diff --git a/htrace-htraced/go/src/org/apache/htrace/htraced/client_test.go b/htrace-htraced/go/src/org/apache/htrace/htraced/client_test.go
index ca0a425..0b38481 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htraced/client_test.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htraced/client_test.go
@@ -30,8 +30,8 @@
"time"
)
-func TestClientGetServerInfo(t *testing.T) {
- htraceBld := &MiniHTracedBuilder{Name: "TestClientGetServerInfo",
+func TestClientGetServerVersion(t *testing.T) {
+ htraceBld := &MiniHTracedBuilder{Name: "TestClientGetServerVersion",
DataDirs: make([]string, 2)}
ht, err := htraceBld.Build()
if err != nil {
@@ -43,9 +43,9 @@
if err != nil {
t.Fatalf("failed to create client: %s", err.Error())
}
- _, err = hcl.GetServerInfo()
+ _, err = hcl.GetServerVersion()
if err != nil {
- t.Fatalf("failed to call GetServerInfo: %s", err.Error())
+ t.Fatalf("failed to call GetServerVersion: %s", err.Error())
}
}
diff --git a/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go b/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
index 2a10805..a41e1c7 100644
--- a/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
+++ b/htrace-htraced/go/src/org/apache/htrace/htraced/rest.go
@@ -50,22 +50,22 @@
w.Write([]byte(`{ "error" : "` + str + `"}`))
}
-type serverInfoHandler struct {
+type serverVersionHandler struct {
lg *common.Logger
}
-func (hand *serverInfoHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+func (hand *serverVersionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
setResponseHeaders(w.Header())
- version := common.ServerInfo{ReleaseVersion: RELEASE_VERSION,
+ version := common.ServerVersion{ReleaseVersion: RELEASE_VERSION,
GitVersion: GIT_VERSION}
buf, err := json.Marshal(&version)
if err != nil {
writeError(hand.lg, w, http.StatusInternalServerError,
- fmt.Sprintf("error marshalling ServerInfo: %s\n", err.Error()))
+ fmt.Sprintf("error marshalling ServerVersion: %s\n", err.Error()))
return
}
if hand.lg.DebugEnabled() {
- hand.lg.Debugf("Returned serverInfo %s\n", string(buf))
+ hand.lg.Debugf("Returned ServerVersion %s\n", string(buf))
}
w.Write(buf)
}
@@ -303,7 +303,8 @@
r := mux.NewRouter().StrictSlash(false)
- r.Handle("/server/info", &serverInfoHandler{lg: rsv.lg}).Methods("GET")
+ r.Handle("/server/info", &serverVersionHandler{lg: rsv.lg}).Methods("GET")
+ r.Handle("/server/version", &serverVersionHandler{lg: rsv.lg}).Methods("GET")
serverStatsH := &serverStatsHandler{dataStoreHandler: dataStoreHandler{
store: store, lg: rsv.lg}}
diff --git a/htrace-htraced/src/test/java/org/apache/htrace/impl/HTracedProcess.java b/htrace-htraced/src/test/java/org/apache/htrace/impl/HTracedProcess.java
index 26c1a10..5c5e394 100644
--- a/htrace-htraced/src/test/java/org/apache/htrace/impl/HTracedProcess.java
+++ b/htrace-htraced/src/test/java/org/apache/htrace/impl/HTracedProcess.java
@@ -255,9 +255,9 @@
"htraced");
}
- public String getServerInfoJson() throws Exception {
+ public String getServerVersionJson() throws Exception {
ContentResponse response = httpClient.GET(
- new URI(String.format("http://%s/server/info", httpAddr)));
+ new URI(String.format("http://%s/server/version", httpAddr)));
Assert.assertEquals("application/json", response.getMediaType());
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
return response.getContentAsString();
diff --git a/htrace-htraced/src/test/java/org/apache/htrace/impl/TestHTracedReceiver.java b/htrace-htraced/src/test/java/org/apache/htrace/impl/TestHTracedReceiver.java
index 99f00a1..0a89ff0 100644
--- a/htrace-htraced/src/test/java/org/apache/htrace/impl/TestHTracedReceiver.java
+++ b/htrace-htraced/src/test/java/org/apache/htrace/impl/TestHTracedReceiver.java
@@ -64,10 +64,10 @@
};
@Test(timeout = 60000)
- public void testGetServerInfoJson() throws Exception {
+ public void testGetServerVersionJson() throws Exception {
HTracedProcess ht = new HTracedProcess.Builder().build();
try {
- String response = ht.getServerInfoJson();
+ String response = ht.getServerVersionJson();
assertTrue(response.contains("ReleaseVersion"));
} finally {
ht.destroy();
diff --git a/htrace-webapp/src/main/webapp/app/router.js b/htrace-webapp/src/main/webapp/app/router.js
index 607da44..dd86b55 100644
--- a/htrace-webapp/src/main/webapp/app/router.js
+++ b/htrace-webapp/src/main/webapp/app/router.js
@@ -23,6 +23,7 @@
"routes": {
"": "empty",
"about": "about",
+ "serverInfo": "serverInfo",
"search": "search",
"*unknown": "unknown"
},
@@ -34,18 +35,40 @@
about: function() {
console.log("Visiting #about.");
- serverInfo = new htrace.ServerInfo();
var router = this;
- serverInfo.fetch({
- "success": function(model, response, options) {
- router.switchView(new htrace.AboutView({model: serverInfo, el: "#app"}));
- router.activateNavBarEntry("about")
- },
- "error": function(model, response, options) {
- window.alert("Failed to fetch htraced server info via GET " +
- "/server/info: " + JSON.stringify(response));
- }
- });
+ router.switchView(new htrace.AboutView({el: "#app"}));
+ router.activateNavBarEntry("about")
+ },
+
+ serverInfo: function() {
+ console.log("Visiting #serverInfo.");
+ var version = new htrace.ServerVersion();
+ var router = this;
+ version.fetch({
+ "error": function(model, response, options) {
+ window.alert("Failed to fetch htraced server version: " +
+ JSON.stringify(response));
+ },
+ "success": function(model, response, options) {
+ stats = new htrace.ServerStats();
+ stats.fetch({
+ "error": function(model, response, options) {
+ window.alert("Failed to fetch htraced server stats: " +
+ JSON.stringify(response));
+ },
+ "success": function(model, response, options) {
+ router.switchView(new htrace.ServerInfoView({
+ model: {
+ "version": version,
+ "stats": stats
+ },
+ el: "#app"
+ }))
+ router.activateNavBarEntry("serverInfo")
+ }
+ })
+ }
+ })
},
search: function() {
diff --git a/htrace-webapp/src/main/webapp/app/server_info.js b/htrace-webapp/src/main/webapp/app/server_configuration.js
similarity index 79%
copy from htrace-webapp/src/main/webapp/app/server_info.js
copy to htrace-webapp/src/main/webapp/app/server_configuration.js
index b03f706..e2684f5 100644
--- a/htrace-webapp/src/main/webapp/app/server_info.js
+++ b/htrace-webapp/src/main/webapp/app/server_configuration.js
@@ -17,15 +17,9 @@
* under the License.
*/
-// htraced ServerInfo sent back from /serverInfo.
-// See rest.go.
-htrace.ServerInfo = Backbone.Model.extend({
- defaults: {
- "ReleaseVersion": "unknown",
- "GitVersion": "unknown",
- },
-
+// htraced server configuration information. See rest.go.
+htrace.ServerConfiguration = Backbone.Model.extend({
url: function() {
- return "server/info";
+ return "server/conf";
}
});
diff --git a/htrace-webapp/src/main/webapp/app/server_info_view.js b/htrace-webapp/src/main/webapp/app/server_info_view.js
new file mode 100644
index 0000000..f8307ff
--- /dev/null
+++ b/htrace-webapp/src/main/webapp/app/server_info_view.js
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+var htrace = htrace || {};
+
+htrace.ServerInfoView = Backbone.View.extend({
+ events: {
+ "click .serverConfigurationButton": "showServerConfigurationModal",
+ },
+
+ render: function() {
+ this.$el.html(_.template($("#server-info-view-template").html())
+ ({ model : this.model,
+ view : this}));
+ console.log("ServerInfoView#render");
+ return this;
+ },
+
+ close: function() {
+ console.log("ServerInfoView#close")
+ this.undelegateEvents();
+ },
+
+ getServerStatsTableHtml: function() {
+ var out =
+ '<div class="panel-heading">' +
+ '<div class="panel-title">Span Metrics</div>' +
+ '</div>' +
+ '<table class="table table-striped">' +
+ '<thead>' +
+ '<tr>' +
+ '<th>Remote</th>' +
+ '<th>Written</th>' +
+ '<th>ServerDropped</th>' +
+ '<th>ClientDropped</th>' +
+ '</tr>' +
+ '</thead>';
+ var remotes = [];
+ var stats = this.model.stats
+ var spanMetrics = stats.get("HostSpanMetrics")
+ for (var remote in spanMetrics) {
+ if (spanMetrics.hasOwnProperty(remote)) {
+ remotes.push(remote)
+ }
+ }
+ remotes = remotes.sort()
+ for (var i = 0; i < remotes.length; i++) {
+ var remote = remotes[0];
+ var smtx = spanMetrics[remote];
+ out = out + "<tr>" +
+ "<td>" + remote + "</td>" +
+ "<td>" + smtx.Written + "</td>" +
+ "<td>" + smtx.ServerDropped + "</td>" +
+ "<td>" + smtx.ClientDropped + "</td>" +
+ "</tr>";
+ }
+ out = out + '</table>';
+ //console.log("out = " + out);
+ return out;
+ },
+
+ showServerConfigurationModal: function() {
+ var config = new htrace.ServerConfiguration();
+ var view = this;
+ config.fetch({
+ "error": function(model, response, options) {
+ window.alert("Failed to fetch htraced server configuration: " +
+ JSON.stringify(response));
+ },
+ "success": function(model, response, options) {
+ var confKeys = [];
+ for (var confKey in model.attributes) {
+ confKeys.push(confKey)
+ }
+ console.log("confKeys = " + JSON.stringify(confKeys));
+ confKeys = confKeys.sort()
+ var out = '<table style="table-layout:fixed;width:100%;word-wrap:break-word">' +
+ '<thead>' +
+ '<tr>' +
+ '<th>Key</th>' +
+ '<th>Value</th>' +
+ '</tr>' +
+ '</thead>';
+ for (var i = 0; i < confKeys.length; i++) {
+ var colorString = ((i%2) == 1) ? "#f1f1f1" : "#ffffff";
+ out += _.template($("#table-row-template").html())(
+ {bgcolor: colorString, key: confKeys[i],
+ val: model.attributes[confKeys[i]]});
+ //out = out + '<tr><th>' + confKeys[i] + '</th><th>' +
+ //model.attributes[confKeys[i]] + '</th></tr>';
+ }
+ var out = out + '</table>';
+ htrace.showModal(_.template($("#modal-table-template").html())(
+ {title: "HTraced Server Configuration", body: out}));
+ }
+ })
+ }
+});
diff --git a/htrace-webapp/src/main/webapp/app/server_info.js b/htrace-webapp/src/main/webapp/app/server_stats.js
similarity index 80%
copy from htrace-webapp/src/main/webapp/app/server_info.js
copy to htrace-webapp/src/main/webapp/app/server_stats.js
index b03f706..e4289ef 100644
--- a/htrace-webapp/src/main/webapp/app/server_info.js
+++ b/htrace-webapp/src/main/webapp/app/server_stats.js
@@ -17,15 +17,13 @@
* under the License.
*/
-// htraced ServerInfo sent back from /serverInfo.
-// See rest.go.
-htrace.ServerInfo = Backbone.Model.extend({
+// htraced server statistics. See rest.go.
+htrace.ServerStats = Backbone.Model.extend({
defaults: {
- "ReleaseVersion": "unknown",
- "GitVersion": "unknown",
+ "ReapedSpans": "(unknown)",
},
url: function() {
- return "server/info";
+ return "server/stats";
}
});
diff --git a/htrace-webapp/src/main/webapp/app/server_info.js b/htrace-webapp/src/main/webapp/app/server_version.js
similarity index 86%
rename from htrace-webapp/src/main/webapp/app/server_info.js
rename to htrace-webapp/src/main/webapp/app/server_version.js
index b03f706..a049324 100644
--- a/htrace-webapp/src/main/webapp/app/server_info.js
+++ b/htrace-webapp/src/main/webapp/app/server_version.js
@@ -17,15 +17,14 @@
* under the License.
*/
-// htraced ServerInfo sent back from /serverInfo.
-// See rest.go.
-htrace.ServerInfo = Backbone.Model.extend({
+// htraced server version information. See rest.go.
+htrace.ServerVersion = Backbone.Model.extend({
defaults: {
"ReleaseVersion": "unknown",
"GitVersion": "unknown",
},
url: function() {
- return "server/info";
+ return "server/version";
}
});
diff --git a/htrace-webapp/src/main/webapp/index.html b/htrace-webapp/src/main/webapp/index.html
index ec28fe6..2cebefe 100644
--- a/htrace-webapp/src/main/webapp/index.html
+++ b/htrace-webapp/src/main/webapp/index.html
@@ -30,6 +30,7 @@
<a class="navbar-brand" href="#">HTrace</a>
<ul class="nav navbar-nav">
<li id="about"><a href="#about">About</a></li>
+ <li id="serverInfo"><a href="#serverInfo">ServerInfo</a></li>
<li id="search"><a href="#search">Search</a></li>
</ul>
</div>
@@ -40,16 +41,58 @@
<footer></footer>
<script id="about-view-template" type="text/template">
+ <div class="row" align="center">
+ <h1>Welcome to <a href="http://htrace.incubator.apache.org/">Apache HTrace</a></h1>
+ </div>
+ <div class="row" align="center">
+ <img src="image/owl.png" width="40%"><p/><p/>
+ </div>
+ </script>
+
+ <script id="server-info-view-template" type="text/template">
<div class="row">
<div class="col-md-1">
</div>
<div class="col-md-10">
- <h1>Welcome to HTrace</h1>
- <img src="image/owl.png" width="15%">
- <h2>Server Version</h2>
- <%= model.get("ReleaseVersion") %>
- <h2>Server Git Hash</h2>
- <%= model.get("GitVersion") %>
+ <h2>HTraced at <%= window.location.host %></h2>
+ <div class="panel panel-info">
+ <div class="panel-heading">
+ <div class="panel-title">Version</div>
+ </div>
+ <table class="table table-striped">
+ <tr>
+ <td>Server Release Version</td>
+ <td><%= model.version.get("ReleaseVersion") %></td>
+ </tr>
+ <tr>
+ <td>Server Git Hash</td>
+ <td><%= model.version.get("GitVersion") %></td>
+ </tr>
+ </table>
+ </div>
+ <div class="panel panel-info">
+ <div class="panel-heading">
+ <div class="panel-title">Global Metrics</div>
+ </div>
+ <table class="table table-striped">
+ <tr>
+ <td>Spans Reaped</td>
+ <td><%= model.stats.get("ReapedSpans") %></td>
+ </tr>
+ </tr>
+ <td>Datastore Start Time</td>
+ <td><%= htrace.dateToString(model.stats.get("LastStartMs")) %></td>
+ </tr>
+ </tr>
+ <td>Current Server Time</td>
+ <td><%= htrace.dateToString(model.stats.get("CurMs")) %></td>
+ </tr>
+ </table>
+ </div>
+ <div class="panel panel-info">
+ <%= view.getServerStatsTableHtml() %>
+ </div>
+ <button type="button" class="btn btn-info serverConfigurationButton">Server Configuration</button>
</div>
<div class="col-md-1">
</div>
@@ -232,13 +275,16 @@
<script src="app/span_widget.js" type="text/javascript"></script>
<script src="app/search_results.js" type="text/javascript"></script>
<script src="app/about_view.js" type="text/javascript"></script>
+ <script src="app/server_info_view.js" type="text/javascript"></script>
<script src="app/modal.js" type="text/javascript"></script>
<script src="app/predicate.js" type="text/javascript"></script>
<script src="app/predicate_view.js" type="text/javascript"></script>
<script src="app/query_results.js" type="text/javascript"></script>
<script src="app/search_results_view.js" type="text/javascript"></script>
<script src="app/search_view.js" type="text/javascript"></script>
- <script src="app/server_info.js" type="text/javascript"></script>
+ <script src="app/server_configuration.js" type="text/javascript"></script>
+ <script src="app/server_stats.js" type="text/javascript"></script>
+ <script src="app/server_version.js" type="text/javascript"></script>
<script src="app/router.js" type="text/javascript"></script>
</body>