http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d0d535c7/src/blur-gui/src/main/webapp/footer.jsp ---------------------------------------------------------------------- diff --git a/src/blur-gui/src/main/webapp/footer.jsp b/src/blur-gui/src/main/webapp/footer.jsp new file mode 100644 index 0000000..b4c3f8a --- /dev/null +++ b/src/blur-gui/src/main/webapp/footer.jsp @@ -0,0 +1,2 @@ + <br/> + <a href="index.html">home</a> | <a href="logs">logs</a> | <a href="metrics.jsp">metrics</a> <a href="metrics" title="Great with plugins like jsonView">(raw)</a> \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d0d535c7/src/blur-gui/src/main/webapp/functions.jsp ---------------------------------------------------------------------- diff --git a/src/blur-gui/src/main/webapp/functions.jsp b/src/blur-gui/src/main/webapp/functions.jsp new file mode 100644 index 0000000..9e5d82b --- /dev/null +++ b/src/blur-gui/src/main/webapp/functions.jsp @@ -0,0 +1,25 @@ + +<%!public String row(String... col) { + String ret = "<tr>"; + for (String c : col) + ret += "<td>" + c + "</td>"; + return ret + "</tr>\n"; + } + + public String row(int colspan, String col) { + return "<tr><td colspan=" + colspan + ">" + col + "</td></tr>"; + } + + public String shardListLink(String cluster, String display) { + return "<a href='shardList.jsp?clusterName=" + cluster + + "' title='view shard servers'>" + display + "</a>"; + } + + public String table(String content, String... headers) { + String ret = "<table class='statTable'><tr>\n"; + for(String h : headers) + ret += "<td class='statTableTitle'>" + h + "</td>\n"; + return ret + "</tr>" + content + "</table>\n"; + } + +%> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d0d535c7/src/blur-gui/src/main/webapp/home.jsp ---------------------------------------------------------------------- diff --git a/src/blur-gui/src/main/webapp/home.jsp b/src/blur-gui/src/main/webapp/home.jsp new file mode 100644 index 0000000..6d47063 --- /dev/null +++ b/src/blur-gui/src/main/webapp/home.jsp @@ -0,0 +1,120 @@ +<%@ page contentType="text/html; charset=UTF-8" isThreadSafe="false" + import="javax.servlet.*" import="javax.servlet.http.*" + import="java.io.*" import="java.util.*" import="java.text.DateFormat" + import="java.lang.Math" import="java.net.URLEncoder" + import="com.nearinfinity.blur.thrift.*" + import="com.nearinfinity.blur.thrift.generated.*" + import="com.nearinfinity.blur.thrift.generated.Blur.*"%> +<%@ include file="functions.jsp" %> +<%! + + public String tableLink(String tableName, String clusterName) { + return "<a href='table.jsp?tableName="+tableName+"&clusterName="+clusterName+"' title='view details for " + tableName + "'>" + tableName + "</a>"; + } + + public String getTables(Iface client) throws Exception { + String ret = ""; + List<String> clusters = client.shardClusterList(); + for (String cluster : clusters) { + //tables: _ tableName : enabled + List<String> tables = client.tableListByCluster(cluster); + for (String table : tables) { + try { + TableDescriptor td = client.describe(table); + ret += row(cluster, tableLink(table,cluster), td.shardCount+"", td.isEnabled?"yes":"no"); + } catch (BlurException e) { + ret += row(3, "<font color=FF0000>Error describing table: " + + table + "</font>"); + } + } + } + return ret; + } + + public String getClusters(Iface client) throws Exception { + String ret = ""; + List<String> clusters = client.shardClusterList(); + for (String cluster : clusters) { + ret += row(cluster, shardListLink(cluster,client.shardServerList(cluster).size()+""), getClusterEnabled(client, cluster)); + } + return ret; + } + + + public String getConf(Iface client) throws Exception { + return row(2,"disabled as its broken"); +/* try { + Map<String, String> config = client.configuration(); + String ret = ""; + for (String key : config.keySet()) { + ret += row(key, config.get(key)); + } + return ret; + } catch (Exception e) { + return row(2, "Cannot retrieve anything from client.configuration."); + }*/ + } + + public String getClusterEnabled(Iface client, String cluster) + throws Exception { + return client.isInSafeMode(cluster) ? "Safe Mode On" + : "Yes"; + } + + public String getControllers(Iface client) throws Exception { + String ret = ""; + List<String> con = client.controllerServerList(); + + for (String c : con) { + String[] split = c.split(":"); + int base = Integer.parseInt(System.getProperty("blur.base.controller.port")); + int offset = Integer.parseInt(split[1])-base; + int baseShardPort = Integer.parseInt(System.getProperty("baseGuiControllerPort")); + ret += row("<a href='http://" + split[0] + ":" + (baseShardPort + offset) + "'>" + c + "</a>","Yes"); + } + + return ret; + }%> +<% + String hostName = request.getServerName() + ":" + System.getProperty("blur.gui.servicing.port"); + + Iface client = BlurClient.getClient(hostName); +%> + + +<html> +<head> +<title>Blur <%=System.getProperty("blur.gui.mode") %> '<%=hostName%>' +</title> +<link href="style.css" rel="stylesheet" type="text/css" /> +</head> +<body> + <h1> + Blur <%=System.getProperty("blur.gui.mode") %> '<%=hostName%>' + </h1> + <br /> + <h2>Controllers</h2> + <%=table(getControllers(client),"Name","Online") %> + <hr /> + <br /> + <h2>Clusters</h2> + <%=table(getClusters(client),"Cluster Name","Shard Servers","Enabled") %> + <hr /> + <br /> + <h2>Tables</h2> + <%=table(getTables(client),"Cluster Name","Table Name","Shards","Enabled")%> + <hr /> + <br /> + <h2>Configs</h2> + <table class="statTable" class="statTableTitle"> + <tr> + <td class="statTableTitle">Param</td> + <td class="statTableTitle">Value</td> + </tr> + <%=getConf(client)%> + </table> + <hr /> +<%@ include file="footer.jsp" %> +</body> + +</html> http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d0d535c7/src/blur-gui/src/main/webapp/index.html ---------------------------------------------------------------------- diff --git a/src/blur-gui/src/main/webapp/index.html b/src/blur-gui/src/main/webapp/index.html new file mode 100644 index 0000000..3a08bc6 --- /dev/null +++ b/src/blur-gui/src/main/webapp/index.html @@ -0,0 +1,13 @@ +<meta HTTP-EQUIV="REFRESH" content="0;url=home.jsp"/> +<html> +<head> +<title>Blur</title> +</head> +<body> +<h1>Blur</h1> + +<ul> +<li><a href="home.jsp">Blur Health/Status</a></li> +</ul> +</body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d0d535c7/src/blur-gui/src/main/webapp/metrics.jsp ---------------------------------------------------------------------- diff --git a/src/blur-gui/src/main/webapp/metrics.jsp b/src/blur-gui/src/main/webapp/metrics.jsp new file mode 100644 index 0000000..73d95b6 --- /dev/null +++ b/src/blur-gui/src/main/webapp/metrics.jsp @@ -0,0 +1,120 @@ +<%@page import="java.text.DecimalFormat"%> +<%@page import="java.text.NumberFormat"%> +<%@ page contentType="text/html; charset=UTF-8" isThreadSafe="false" + import="javax.servlet.*" import="javax.servlet.http.*" + import="java.io.*" import="java.util.*" import="java.text.DateFormat" + import="java.lang.Math" import="java.net.URLEncoder" + import="com.nearinfinity.blur.thrift.*" + import="com.nearinfinity.blur.thrift.generated.*" + import="com.nearinfinity.blur.thrift.generated.Blur.*"%> +<%@ include file="functions.jsp"%> +<% + String hostName = request.getServerName() + ":" + System.getProperty("blur.gui.servicing.port"); +%> +<html> +<head> +<title>Metrics +</title> + +<link href="style.css" rel="stylesheet" type="text/css" /> + +</head> + +<script src="d3.v2.js"></script> +<body> + <script> + //decimal formatter + var df = d3.format(","); + var df1dp = d3.format("3,.1f"); + var methodCalls; + + + //basic printout + d3.json("metrics", function(json) { + + methodCalls = json["methodCalls"]; + delete json["methodCalls"]; + + var topLevelMetrics = d3.entries(json); + + var columns = ["stat", "value"]; + + var table = d3.select("#leftTD").append("table"), + thead = table.append("thead"), + tbody = table.append("tbody"); + + // append the header row + thead.append("tr") + .selectAll("th") + .data(columns) + .enter() + .append("th") + .text(function(column) { return column; }) + .style("text-align", function(d) { return "left"}); + + // create a row for each object in the data + var rows = tbody.selectAll("tr") + .data(topLevelMetrics) + .enter() + .append("tr") + .style("background-color", function(d,i) { return i % 2 ? "#eee" : "#ddd"; }); + + // create a cell in each row for each column + var cells = rows.selectAll("td") + .data(function(row) { + return d3.entries(row); + }) + .enter() + .append("td") + .text(function(d) { return d.value; }); + + var nsToS = 1000000000; + + //alert(json); + arr = []; + arr[0] = json; + + var rTable = d3.select("#rightTD").append("table"), + rHead = rTable.append("thead"), + rBody = rTable.append("tbody"); + + rHead.append("tr") + .selectAll("th") + .data(["MethodCall","rate (s)","invokes","times (ns)"]) + .enter() + .append("th") + .text(function(column) { return column; }) + .style("text-align", function(d) { return "left"}); + + var rrows = rBody.selectAll("tr") + .data(d3.keys(methodCalls)) + .enter() + .append("tr") + .style("background-color", function(d,i) { return i % 2 ? "#eee" : "#ddd"; }); + + rrows.selectAll("td") + .data(function(d,i) { return [d, + df1dp(methodCalls[d].invokes/(methodCalls[d].times/nsToS)), + df(methodCalls[d].invokes), + methodCalls[d].times] } ) + .enter() + .append("td") + .text(function(d) { return d; }); + }); + </script> + <h1> + Blur <%=System.getProperty("blur.gui.mode") %> '<%=hostName%>' + </h1> + <br /> + <table> + <tr> + <td width="400" id="leftTD" valign="top"></td> + <td width="400" id="rightTD" valign="top"></td> + </tr> + </table> +<div> +</div> +<%@ include file="footer.jsp" %> +</body> +</html> + http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d0d535c7/src/blur-gui/src/main/webapp/shardList.jsp ---------------------------------------------------------------------- diff --git a/src/blur-gui/src/main/webapp/shardList.jsp b/src/blur-gui/src/main/webapp/shardList.jsp new file mode 100644 index 0000000..5bab8ce --- /dev/null +++ b/src/blur-gui/src/main/webapp/shardList.jsp @@ -0,0 +1,60 @@ +<%@ page contentType="text/html; charset=UTF-8" isThreadSafe="false" + import="javax.servlet.*" import="javax.servlet.http.*" + import="java.io.*" import="java.util.*" import="java.text.DateFormat" + import="java.lang.Math" import="java.net.URLEncoder" + import="com.nearinfinity.blur.thrift.*" + import="com.nearinfinity.blur.thrift.generated.*" + import="com.nearinfinity.blur.thrift.generated.Blur.*"%> +<%@ include file="functions.jsp"%> +<%! + public String shards(Iface client, String clusterName) throws Exception { + String ret = ""; + List<String> servers = client.shardServerList(clusterName); + + for(String s : servers) { + String[] split = s.split(":"); + int base = Integer.parseInt(System.getProperty("blur.base.shard.port")); + int offset = Integer.parseInt(split[1])-base; + int baseShardPort = Integer.parseInt(System.getProperty("baseGuiShardPort")); + ret += row("<a href='http://" + split[0] + ":" + (baseShardPort + offset) + "'>" + s + "</a>","",""); + + } + return ret; + } +%> + +<% + //TODO: prop file the port + String hostName = request.getServerName() + ":" + System.getProperty("blur.gui.servicing.port"); + + Iface client = BlurClient.getClient(hostName); + + String clusterName = request.getParameter("clusterName"); +%> + +<html> +<head> +<title>Blur Cluster Shard List '<%=hostName%>' +</title> +<link href="style.css" rel="stylesheet" type="text/css" /> +</head> +<body> + <% + if (clusterName == null) { + %> + No cluster specified, go home. + <% + } else { + %> + <h1> + Blur Shard List for Cluster '<%=clusterName%>' + </h1> + <br /> + <%=table(shards(client, clusterName),"Shard") %> + + <% + } + %> +<%@ include file="footer.jsp" %> +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d0d535c7/src/blur-gui/src/main/webapp/style.css ---------------------------------------------------------------------- diff --git a/src/blur-gui/src/main/webapp/style.css b/src/blur-gui/src/main/webapp/style.css new file mode 100644 index 0000000..cda4fb7 --- /dev/null +++ b/src/blur-gui/src/main/webapp/style.css @@ -0,0 +1,53 @@ +body { + font-family: sans-serif; + font-size: 11px; + line-height: 17px; +} + +a { + color: #0044FF !important; + text-decoration: none !important; +} + +h2 { + margin: 5px 5px 0px 0px; +} + +hr { + -moz-border-bottom-colors: none; + -moz-border-image: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; + border-color: -moz-use-text-color #DDDDDD #DDDDDD; + border-right: 1px solid #DDDDDD; + border-style: none solid solid; + border-width: 0 1px 1px; +} + +table { + font-size: 12px; + +} + +td { + align: left; + font-size: 12px; + padding-left: 10px; + padding-right: 10px; + font-family: Verdana; +} + +.statTable { + width: 500px; +} + +.statTableTitle { + color: 55555; + align: left; + font-weight: bold; + font-size:14pt; + padding: 10px 5px 0px 5px; + font-family: Helvetica; + background-color: #DDDDDD; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d0d535c7/src/blur-gui/src/main/webapp/table.jsp ---------------------------------------------------------------------- diff --git a/src/blur-gui/src/main/webapp/table.jsp b/src/blur-gui/src/main/webapp/table.jsp new file mode 100644 index 0000000..a8adbef --- /dev/null +++ b/src/blur-gui/src/main/webapp/table.jsp @@ -0,0 +1,153 @@ +<%@page import="java.text.DecimalFormat"%> +<%@page import="java.text.NumberFormat"%> +<%@ page contentType="text/html; charset=UTF-8" isThreadSafe="false" + import="javax.servlet.*" import="javax.servlet.http.*" + import="java.io.*" import="java.util.*" import="java.text.DateFormat" + import="java.lang.Math" import="java.net.URLEncoder" + import="com.nearinfinity.blur.thrift.*" + import="com.nearinfinity.blur.thrift.generated.*" + import="com.nearinfinity.blur.thrift.generated.Blur.*"%> +<%@ include file="functions.jsp"%> +<%!public boolean tableInSafeMode(Iface client, String clusterName) throws Exception { + return client.isInSafeMode(clusterName); + } + + public String getStats(Iface client, String tableName) throws Exception { + DecimalFormat df = new DecimalFormat("#,###,###,###0.00"); + String ret = ""; + + TableStats ts = client.getTableStats(tableName); + String size = ""; + //bytes + if(ts.bytes < 1000) + size = ts.bytes + " bytes"; + //kb + else if(ts.bytes < 1048576) + size = df.format(ts.bytes/1000.0) + " KB"; + else if(ts.bytes < 1073741824) + size = df.format(ts.bytes/1000.0/1000) + " MB"; + else if(ts.bytes < 137438953472l) + size = df.format(ts.bytes/1000.0/1000/1000) + " GB"; + else if(ts.bytes < 1099511627776l) + size = df.format(ts.bytes/1000.0/1000/1000/1000) + " TB"; + ret += row("size", size); + ret += row("Queries", ts.queries + ""); + ret += row("Rows", ts.rowCount + ""); + ret += row("Records", ts.recordCount + ""); + TableDescriptor td = client.describe(tableName); + ret += row("Block Caching", td.blockCaching + ""); + ret += row("Compression Block Size", td.compressionBlockSize + ""); + ret += row("Compression Class", td.compressionClass); + ret += row("Read Only", td.readOnly + ""); + + + return ret; + } + + public String getSchema(Iface client, String tableName) throws Exception { + String ret = ""; + + Schema s = client.schema(tableName); + for (String fam : s.columnFamilies.keySet()) { + String tmp = ""; + for (String c : s.columnFamilies.get(fam)) + tmp += c + ", "; + if (!"".equals(tmp)) + tmp = tmp.substring(0, tmp.length() - 2); + ret += row(fam, tmp); + } + + return ret; + } + + public String getAD(Iface client, String tableName) throws Exception { + String ret = ""; + + TableDescriptor td = client.describe(tableName); + AnalyzerDefinition ad = td.analyzerDefinition; + Map<String, ColumnFamilyDefinition> cfds = ad.columnFamilyDefinitions; + for (String cf : cfds.keySet()) { + ColumnFamilyDefinition cfd = cfds.get(cf); + if (cfd.defaultDefinition != null) + ret += row(cf, "default", + cfd.defaultDefinition.analyzerClassName); + else + ret += row(cf, "default", "none set"); + for (String col : cfd.columnDefinitions.keySet()) { + ret += row("", col, + cfd.columnDefinitions.get(col).analyzerClassName); + } + } + + return ret; + }%> +<% + final String NONE = "none given"; + + String hostName = request.getServerName() + ":" + System.getProperty("blur.gui.servicing.port"); + + Iface client = BlurClient.getClient(hostName); + + String tableName = request.getParameter("tableName"); + String clusterName = request.getParameter("clusterName"); + + if (tableName == null || tableName.length() < 1) { + tableName = NONE; + } + + if (clusterName == null || clusterName.length() < 1) { + clusterName = NONE; + } +%> + + +<html> +<head> +<title>Table '<%=tableName%>' +</title> + +<link href="style.css" rel="stylesheet" type="text/css" /> + +</head> + +<body> + <% + if (NONE.equals(clusterName) || NONE.equals(tableName)) { + %> + Dont have a cluster and tableName specified, go home. + <% + } else { + %> + <h1> + Table '<%=tableName%>' + </h1> + <% + if (tableInSafeMode(client, clusterName)) { + %> + Cluster + <%=clusterName%> + is in safe mode, cannot retrieve table information yet. + <% + } else { + %> + + <h2>Stats</h2> + <%=table(getStats(client, tableName), "Stat", + "Value")%> + <br /> + <h2>Schema</h2> + <%=table(getSchema(client, tableName), + "ColumnFamily", "Column")%> + <br /> + <h2>Field Definitions</h2> + <%=table(getAD(client, tableName), "ColumnFamily", + "Column", "Analyzer")%> + + <% + } + } + %> +<%@ include file="footer.jsp" %> +</body> +</html> + http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d0d535c7/src/blur-gui/src/main/webapp/test.html ---------------------------------------------------------------------- diff --git a/src/blur-gui/src/main/webapp/test.html b/src/blur-gui/src/main/webapp/test.html new file mode 100644 index 0000000..034ba04 --- /dev/null +++ b/src/blur-gui/src/main/webapp/test.html @@ -0,0 +1,123 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<style> +svg { + font: 10px sans-serif; +} + +.line { + fill: none; + stroke: #000; + stroke-width: 1.5px; +} + +.axis path,.axis line { + fill: none; + stroke: #000; + shape-rendering: crispEdges; +} + +div { + background: #CCC; +} + +</style> + +</head> + +<script src="d3.v2.js"></script> +<body> + <script> + //decimal formatter + var df = d3.format("4d"); + + //basic printout + d3.json("metrics", function(json) { + //alert(json); + arr = []; + arr[0] = json; + //select obj and bind data + d3.select("body").selectAll("ul") + .data(arr) + .enter().append("ul") + .text("Metrics") + .selectAll("li") + .data(function(d) { + var map = []; + var i = 0; + for(var x in d) { + var obj = {}; + obj.name = x; + obj.value = d[x]; + map[i++] = obj; + } + return map}) + .enter() + .append("li") + .text(function(d) { return d.name + " " + d.value }) + .style("background-color", function(d,i) { return i % 2 ? "#eee" : "#ddd"; }); + }); + + + + //realtime update stuffs + + //data holder + var dummy = []; + + var total = 10; + for(i=0;i<total-1;i++) + dummy.push(0); + + var div = null; + + //not sure why i have to init inside the json method + d3.json("metrics", function(json) { + dummy.push(d3.round(json.methodCalls.mutate.invokes + / (json.methodCalls.mutate.times / 1000000000.0), 3)); + + //select obj and bind data + div = d3.select("body") + .selectAll("div") + .data(dummy) + .enter() + .append("div") + .append("p") + .text(function(d) { return d + " mutates/s"}); + dummy.shift(); + + }); + + if(dummy === undefined) + alert("no metrics for mutates"); + + function tock() { + d3.json("metrics", function(json) { + dummy.push(d3.round(json.methodCalls.mutate.invokes + / (json.methodCalls.mutate.times / 1000000000.0), 3)); + + alert("dummy.length: " + dummy.length + " dummy: " + dummy); + + div.transition() + .duration(1000) + .ease("linear") + //.text(function(d,i) { alert(d + " " + i);return d + " mutates/s"}) + .each("end",tock()); + dummy.shift(); + }); + } + + tock(); + + //after data add? +// div.enter().append("span").text(function(d) { +// return d + "<br/>\n"; +// }) + + + </script> + +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d0d535c7/src/blur-gui/src/main/webapps/controller/WEB-INF/web.xml ---------------------------------------------------------------------- diff --git a/src/blur-gui/src/main/webapps/controller/WEB-INF/web.xml b/src/blur-gui/src/main/webapps/controller/WEB-INF/web.xml deleted file mode 100644 index a35ac56..0000000 --- a/src/blur-gui/src/main/webapps/controller/WEB-INF/web.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" - version="2.5"> - - <display-name>Blur GUI</display-name> -</web-app> \ No newline at end of file
