HTRACE-121. Details page: Graph parents and children
Project: http://git-wip-us.apache.org/repos/asf/incubator-htrace/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-htrace/commit/61738b5a Tree: http://git-wip-us.apache.org/repos/asf/incubator-htrace/tree/61738b5a Diff: http://git-wip-us.apache.org/repos/asf/incubator-htrace/diff/61738b5a Branch: refs/heads/master Commit: 61738b5abddc8a046a535ff703dfa2c3ceb56b52 Parents: a9a4f41 Author: Abraham Elmahrek <[email protected]> Authored: Sat Feb 28 16:30:30 2015 -0800 Committer: Abraham Elmahrek <[email protected]> Committed: Mon Mar 16 15:39:55 2015 -0700 ---------------------------------------------------------------------- htrace-core/src/web/app/setup.js | 19 +- htrace-core/src/web/app/views/graph/graph.js | 203 + htrace-core/src/web/index.html | 62 +- htrace-core/src/web/lib/css/main.css | 12 + htrace-core/src/web/lib/js/d3-3.5.5.js | 9504 +++++++++++++++++++++ 5 files changed, 9761 insertions(+), 39 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/61738b5a/htrace-core/src/web/app/setup.js ---------------------------------------------------------------------- diff --git a/htrace-core/src/web/app/setup.js b/htrace-core/src/web/app/setup.js index ddeec5e..a0c1b07 100644 --- a/htrace-core/src/web/app/setup.js +++ b/htrace-core/src/web/app/setup.js @@ -77,12 +77,25 @@ var Router = Backbone.Marionette.AppRouter.extend({ }, "span": function(id) { + var span = this.spansCollection.findWhere({ + "spanId": id + }); + + if (!span) { + Backbone.history.navigate("!/search", {"trigger": true}); + return; + } + var top = new app.DetailsView(); app.root.app.show(top); top.span.show(new app.SpanDetailsView({ - "model": this.spansCollection.findWhere({ - "spanId": id - }) + "model": span + })); + top.content.show(new app.GraphView({ + "collection": this.spansCollection, + "spanId": id, + "el": top.content.$el[0], + "id": "span-" + id })); } }); http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/61738b5a/htrace-core/src/web/app/views/graph/graph.js ---------------------------------------------------------------------- diff --git a/htrace-core/src/web/app/views/graph/graph.js b/htrace-core/src/web/app/views/graph/graph.js new file mode 100644 index 0000000..def16d3 --- /dev/null +++ b/htrace-core/src/web/app/views/graph/graph.js @@ -0,0 +1,203 @@ +/* + * 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. + */ + +app.GraphView = Backbone.View.extend({ + "MAX_NODE_SIZE": 100, + "MIN_NODE_SIZE": 30, + + initialize: function(options) { + options = options || {}; + _.bindAll(this, "render"); + this.collection.bind('change', this.render); + + if (!options.id) { + console.error("GraphView requires argument 'id' to uniquely identify this graph."); + return; + } + if (!options.el) { + console.error("GraphView requires argument 'el' to bind the graph to."); + return; + } + if (!options.spanId) { + console.error("GraphView requires argument 'spanId' as a start point."); + return; + } + + this.spanId = options.spanId; + + window.force = this.force + = d3.layout.force().size([1000, 1000]) + .alpha(0.1) + .linkDistance(this.MAX_NODE_SIZE*2) + .charge(-600) + .linkDistance(150) + .linkStrength(1) + .friction(0.2) + // .gravity(0.1) + ; + + force.on("tick", function(e) { + var root = d3.select("#" + options.id); + + // Push sources up and targets down to form a weak tree. + var k = 10 * e.alpha; + force.links().forEach(function(d, i) { + d.source.y -= k; + d.target.y += k; + }); + + // set selected node in the middle. + // var selectedNode = force.nodes()[0]; + // selectedNode.x = 500; + // selectedNode.y = 500; + + var nodes = root.selectAll(".node").data(force.nodes()); + nodes.select("circle") + .attr("cx", function(d) { return d.x; }) + .attr("cy", function(d) { return d.y; }); + nodes.select("text") + .attr("x", function(d) { return d.x; }) + .attr("y", function(d) { return d.y; }); + root.selectAll(".link").data(force.links()) + .attr("x1", function(d) { return d.source.x; }) + .attr("y1", function(d) { return d.source.y; }) + .attr("x2", function(d) { return d.target.x; }) + .attr("y2", function(d) { return d.target.y; }); + }); + }, + + parents: function(span) { + var collection = this.collection; + return _(span.get("parents")).map(function(parentSpanId) { + collection.findWhere({ + "spanId": parentSpanId + }); + }); + }, + + children: function(span) { + var spanId = span.get("spanId"); + return this.collection.filter(function(model) { + return _(model.get("parents")).contains(spanId); + }); + }, + + linksAndNodes: function() { + var links = [], + nodes = []; + var selectedSpan = this.collection.findWhere({ + "spanId": this.spanId + }); + var parents = this.parents(selectedSpan); + var children = this.children(selectedSpan); + + var group = 0; + var spanToNode = (function() { + var xmap = {}; + return function(span, level) { + return { + "name": span.get("description"), + "span": span + }; + } + })(); + var createLink = function(source, target) { + return { + "source": source, + "target": target + }; + }; + + var selectedSpanNode = spanToNode(selectedSpan, 1); + nodes.push(selectedSpanNode); + + _(parents).each(function(span) { + var node = spanToNode(span, 0); + nodes.push(node); + links.push(createLink(node, selectedSpanNode)); + }); + + _(children).each(function(span) { + var node = spanToNode(span, 2); + nodes.push(node); + links.push(createLink(selectedSpanNode, node)); + }); + + return { + "links": links, + "nodes": nodes + }; + }, + + renderLinks: function(selection) { + selection.append("line") + .attr("class", "link"); + return selection; + }, + + renderNodes: function(selection) { + var MAX_NODE_SIZE = this.MAX_NODE_SIZE, + MIN_NODE_SIZE = this.MIN_NODE_SIZE; + var g = selection.append("g").attr("class", "node"); + g.append("circle") + .attr("r", function(d) { + var reduced = Math.log(d.span.duration()); + + if (reduced > MAX_NODE_SIZE) { + return MAX_NODE_SIZE; + } + + if (reduced < MIN_NODE_SIZE) { + return MIN_NODE_SIZE; + } + + return reduced; + }); + var text = g.append("text").text(function(d) { + return d.name; + }); + + return selection; + }, + + render: function() { + var svg = d3.select(this.$el[0]).append("svg") + .attr("height", 1000) + .attr("width", 1000) + .attr("id", this.id); + var data = this.linksAndNodes(); + + this.force + .nodes(data.nodes) + .links(data.links) + .start(); + + var link = this.renderLinks( + svg.selectAll(".link") + .data(this.force.links()) + .enter()); + + var node = this.renderNodes( + svg.selectAll(".node") + .data(this.force.nodes()) + .enter()); + + return this; + } +}); http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/61738b5a/htrace-core/src/web/index.html ---------------------------------------------------------------------- diff --git a/htrace-core/src/web/index.html b/htrace-core/src/web/index.html index c57bc4c..ecb0d7e 100644 --- a/htrace-core/src/web/index.html +++ b/htrace-core/src/web/index.html @@ -131,6 +131,8 @@ <div class="col-md-12" role="main"></div> </div> + <hr> + <div class="row"> <div class="col-md-12" role="complementary"></div> </div> @@ -138,44 +140,32 @@ </script> <script id="span-details-template" type="text/html"> - <div class="page-header"> - <h1><%- span.description %></h1> - </div> - <div class="page-contents"> - <div class="row"> - <div class="col-md-2"> - <h4>Span id</h4> - </div> - <div class="col-md-10"><%- span.spanId %></div> - </div> - <div class="row"> - <div class="col-md-2"> - <h4>Process id</h4> - </div> - <div class="col-md-10"><%- span.processId %></div> - </div> - <div class="row"> - <div class="col-md-2"> - <h4>Begin time</h4> - </div> - <div class="col-md-10"><%- span.beginTime %></div> - </div> - <div class="row"> - <div class="col-md-2"> - <h4>End time</h4> - </div> - <div class="col-md-10"><%- span.stopTime %></div> - </div> - <div class="row"> - <div class="col-md-2"> - <h4>Duration</h4> - </div> - <div class="col-md-10"><%- span.duration %></div> - </div> - </div> + <table class="table table-condensed"> + <thead> + <tr> + <th>Description</th> + <th>Span ID</th> + <th>Process ID</th> + <th>Start time</th> + <th>End time</th> + <th>Duration</th> + </tr> + </thead> + <tbody> + <tr> + <td><%- span.description %></td> + <td><%- span.spanId %></td> + <td><%- span.processId %></td> + <td><%- span.beginTime %></td> + <td><%- span.stopTime %></td> + <td><%- span.duration %></td> + </tr> + </tbody> + </table> </script> <script src="lib/js/jquery-2.1.3.min.js" type="text/javascript"></script> + <script src="lib/js/d3-3.5.5.js" type="text/javascript"></script> <script src="lib/bootstrap-3.3.1/js/bootstrap.min.js" type="text/javascript"></script> <script src="lib/js/underscore-1.7.0.js" type="text/javascript"></script> <script src="lib/js/backbone-1.1.2.js" type="text/javascript"></script> @@ -188,7 +178,7 @@ <script src="app/app.js" type="text/javascript"></script> <script src="app/models/span.js" type="text/javascript"></script> - + <script src="app/views/graph/graph.js" type="text/javascript"></script> <script src="app/views/search/field.js" type="text/javascript"></script> <script src="app/views/search/search.js" type="text/javascript"></script> <script src="app/views/details/details.js" type="text/javascript"></script> http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/61738b5a/htrace-core/src/web/lib/css/main.css ---------------------------------------------------------------------- diff --git a/htrace-core/src/web/lib/css/main.css b/htrace-core/src/web/lib/css/main.css index d5fd84f..c0a8f3e 100644 --- a/htrace-core/src/web/lib/css/main.css +++ b/htrace-core/src/web/lib/css/main.css @@ -26,3 +26,15 @@ li.span { margin: 0px; list-style: none; } + +/* Graph */ +svg .node circle { + stroke: #006600; + stroke-width: 3; + fill: #00CC00; +} + +svg .link { + stroke: black; + stroke-width: 3; +} \ No newline at end of file
