mirror of https://github.com/apache/lucene.git
SOLR-3174: Visualize Cluster State
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1328330 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a441ffd1a2
commit
71cd0b00c1
|
@ -5,11 +5,12 @@
|
|||
|
||||
#content #cloud #navigation
|
||||
{
|
||||
width: 10%;
|
||||
width: 11%;
|
||||
}
|
||||
|
||||
#content #cloud #navigation .tree a { background-image: url( ../../img/ico/folder-tree.png ); }
|
||||
#content #cloud #navigation .graph a { background-image: url( ../../img/ico/molecule.png ); }
|
||||
#content #cloud #navigation .rgraph a { background-image: url( ../../img/ico/asterisk.png ); }
|
||||
#content #cloud #navigation .dump a { background-image: url( ../../img/ico/download-cloud.png ); }
|
||||
|
||||
#content #cloud #navigation .dump
|
||||
|
@ -25,7 +26,7 @@
|
|||
#content #cloud #frame
|
||||
{
|
||||
float: right;
|
||||
width: 89%;
|
||||
width: 88%;
|
||||
}
|
||||
|
||||
#content #cloud #frame .content
|
||||
|
@ -249,17 +250,98 @@
|
|||
color: #00f;
|
||||
}
|
||||
|
||||
#content #graph-content .node
|
||||
{
|
||||
fill: #333;
|
||||
}
|
||||
|
||||
#content #graph-content .node circle
|
||||
{
|
||||
fill: #f0f0f0;
|
||||
fill: #fff;
|
||||
stroke: #c0c0c0;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
#content #graph-content .node.lvl-2 text
|
||||
{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#content #graph-content .node.lvl-2:hover circle
|
||||
{
|
||||
stroke: #000 !important;
|
||||
}
|
||||
|
||||
#content #graph-content .node.lvl-2:hover text
|
||||
{
|
||||
fill: #000 !important;
|
||||
}
|
||||
|
||||
#content #graph-content .link
|
||||
{
|
||||
fill: none;
|
||||
stroke: #c0c0c0;
|
||||
stroke: #e0e0e0;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
#content #graph-content .node.gone circle,
|
||||
#content #graph-content .link.gone
|
||||
{
|
||||
stroke: #f0f0f0;
|
||||
}
|
||||
|
||||
#content #graph-content .node.gone text
|
||||
{
|
||||
fill: #f0f0f0;
|
||||
}
|
||||
|
||||
#content #graph-content .node.recovery_failed circle
|
||||
{
|
||||
stroke: #C43C35;
|
||||
}
|
||||
|
||||
#content #graph-content .node.recovery_failed text
|
||||
{
|
||||
fill: #C43C35;
|
||||
}
|
||||
|
||||
#content #graph-content .node.down circle
|
||||
{
|
||||
stroke: #c48f00;
|
||||
}
|
||||
|
||||
#content #graph-content .node.down text
|
||||
{
|
||||
fill: #c48f00;
|
||||
}
|
||||
|
||||
#content #graph-content .node.recovering circle
|
||||
{
|
||||
stroke: #d5dd00;
|
||||
}
|
||||
|
||||
#content #graph-content .node.recovering text
|
||||
{
|
||||
fill: #d5dd00;
|
||||
}
|
||||
|
||||
#content #graph-content .node.active circle
|
||||
{
|
||||
stroke: #57A957;
|
||||
}
|
||||
|
||||
#content #graph-content .node.active text
|
||||
{
|
||||
fill: #57A957;
|
||||
}
|
||||
|
||||
#content #graph-content .node.leader circle
|
||||
{
|
||||
fill: #000;
|
||||
}
|
||||
|
||||
#content #graph-content .link.lvl-1,
|
||||
#content #graph-content .link.leader
|
||||
{
|
||||
stroke: #c0c0c0;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 682 B |
|
@ -153,10 +153,81 @@ var init_debug = function( cloud_element )
|
|||
);
|
||||
};
|
||||
|
||||
var generate_graph = function( graph_element, graph_data )
|
||||
var helper_path_class = function( p )
|
||||
{
|
||||
var w = 900,
|
||||
h = 300;
|
||||
var classes = [ 'link' ];
|
||||
classes.push( 'lvl-' + p.target.depth );
|
||||
|
||||
if( p.target.data.leader )
|
||||
{
|
||||
classes.push( 'leader' );
|
||||
}
|
||||
|
||||
if( p.target.data.state )
|
||||
{
|
||||
classes.push( p.target.data.state );
|
||||
}
|
||||
|
||||
return classes.join( ' ' );
|
||||
};
|
||||
|
||||
var helper_node_class = function( d )
|
||||
{
|
||||
var classes = [ 'node' ];
|
||||
classes.push( 'lvl-' + d.depth );
|
||||
|
||||
if( d.data.leader )
|
||||
{
|
||||
classes.push( 'leader' );
|
||||
}
|
||||
|
||||
if( d.data.state )
|
||||
{
|
||||
classes.push( d.data.state );
|
||||
}
|
||||
|
||||
return classes.join( ' ' );
|
||||
};
|
||||
|
||||
var helper_data = {
|
||||
protocol: [],
|
||||
host: [],
|
||||
hostname: [],
|
||||
port: [],
|
||||
pathname: []
|
||||
};
|
||||
|
||||
var helper_node_text = function( d )
|
||||
{
|
||||
if( !d.data.uri )
|
||||
{
|
||||
return d.name;
|
||||
}
|
||||
|
||||
var name = d.data.uri.hostname;
|
||||
|
||||
if( 1 !== helper_data.protocol.length )
|
||||
{
|
||||
name = d.data.uri.protocol + '//' + name;
|
||||
}
|
||||
|
||||
if( 1 !== helper_data.port.length )
|
||||
{
|
||||
name += ':' + d.data.uri.port;
|
||||
}
|
||||
|
||||
if( 1 !== helper_data.pathname.length )
|
||||
{
|
||||
name += d.data.uri.pathname;
|
||||
}
|
||||
|
||||
return name;
|
||||
};
|
||||
|
||||
var generate_graph = function( graph_element, graph_data, leaf_count )
|
||||
{
|
||||
var w = graph_element.width(),
|
||||
h = leaf_count * 20;
|
||||
|
||||
var tree = d3.layout.tree()
|
||||
.size([h, w - 400]);
|
||||
|
@ -164,80 +235,117 @@ var generate_graph = function( graph_element, graph_data )
|
|||
var diagonal = d3.svg.diagonal()
|
||||
.projection(function(d) { return [d.y, d.x]; });
|
||||
|
||||
var vis = d3.select("#canvas").append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h)
|
||||
.append("g")
|
||||
.attr("transform", "translate(100, 0)");
|
||||
var vis = d3.select( '#canvas' ).append( 'svg' )
|
||||
.attr( 'width', w )
|
||||
.attr( 'height', h)
|
||||
.append( 'g' )
|
||||
.attr( 'transform', 'translate(100, 0)' );
|
||||
|
||||
var nodes = tree.nodes( graph_data );
|
||||
|
||||
var link = vis.selectAll("path.link")
|
||||
var link = vis.selectAll( 'path.link' )
|
||||
.data( tree.links( nodes ) )
|
||||
.enter().append("path")
|
||||
.attr("class", "link")
|
||||
.attr("d", diagonal);
|
||||
.enter().append( 'path' )
|
||||
.attr( 'class', helper_path_class )
|
||||
.attr( 'd', diagonal );
|
||||
|
||||
var node = vis.selectAll("g.node")
|
||||
var node = vis.selectAll( 'g.node' )
|
||||
.data( nodes )
|
||||
.enter().append("g")
|
||||
.attr("class", "node")
|
||||
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
|
||||
.enter().append( 'g' )
|
||||
.attr( 'class', helper_node_class )
|
||||
.attr( 'transform', function(d) { return 'translate(' + d.y + ',' + d.x + ')'; } )
|
||||
|
||||
node.append("circle")
|
||||
.attr("r", 4.5);
|
||||
node.append( 'circle' )
|
||||
.attr( 'r', 4.5 );
|
||||
|
||||
node.append("text")
|
||||
.attr("dx", function(d) { return d.children ? -8 : 8; })
|
||||
.attr("dy", 3)
|
||||
.attr("text-anchor", function(d) { return d.children ? "end" : "start"; })
|
||||
.text(function(d) { return d.name; });
|
||||
node.append( 'text' )
|
||||
.attr( 'dx', function( d ) { return 0 === d.depth ? -8 : 8; } )
|
||||
.attr( 'dy', function( d ) { return 5; } )
|
||||
.attr( 'text-anchor', function( d ) { return 0 === d.depth ? 'end' : 'start'; } )
|
||||
.attr( 'data-href', function( d ) { return d.name; } )
|
||||
.text( helper_node_text );
|
||||
|
||||
/*
|
||||
var r = 860 / 2;
|
||||
$( 'text[data-href*="//"]', graph_element )
|
||||
.die( 'click' )
|
||||
.live
|
||||
(
|
||||
'click',
|
||||
function()
|
||||
{
|
||||
location.href = $( this ).data( 'href' );
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
var tree = d3.layout.tree()
|
||||
.size([360, r - 120])
|
||||
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
|
||||
var generate_rgraph = function( graph_element, graph_data, leaf_count )
|
||||
{
|
||||
var max_val = Math.min( graph_element.width(), $( 'body' ).height() )
|
||||
var r = max_val / 2;
|
||||
|
||||
var cluster = d3.layout.cluster()
|
||||
.size([360, r - 160]);
|
||||
|
||||
var diagonal = d3.svg.diagonal.radial()
|
||||
.projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
|
||||
|
||||
var vis = d3.select("#canvas").append("svg")
|
||||
.attr("width", r * 2)
|
||||
.attr("height", r * 2 - 150)
|
||||
.append("g")
|
||||
.attr("transform", "translate(" + r + "," + r + ")");
|
||||
var vis = d3.select( '#canvas' ).append( 'svg' )
|
||||
.attr( 'width', r * 2 )
|
||||
.attr( 'height', r * 2 )
|
||||
.append( 'g' )
|
||||
.attr( 'transform', 'translate(' + r + ',' + r + ')' );
|
||||
|
||||
var nodes = tree.nodes(graph_data);
|
||||
var nodes = cluster.nodes( graph_data );
|
||||
|
||||
var link = vis.selectAll("path.link")
|
||||
.data(tree.links(nodes))
|
||||
.enter().append("path")
|
||||
.attr("class", "link")
|
||||
.attr("d", diagonal);
|
||||
var link = vis.selectAll( 'path.link' )
|
||||
.data( cluster.links( nodes ) )
|
||||
.enter().append( 'path' )
|
||||
.attr( 'class', helper_path_class )
|
||||
.attr( 'd', diagonal );
|
||||
|
||||
var node = vis.selectAll("g.node")
|
||||
var node = vis.selectAll( 'g.node' )
|
||||
.data( nodes )
|
||||
.enter().append("g")
|
||||
.attr("class", "node")
|
||||
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
|
||||
.enter().append( 'g' )
|
||||
.attr( 'class', helper_node_class )
|
||||
.attr( 'transform', function(d) { return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')'; } )
|
||||
|
||||
node.append("circle")
|
||||
.attr("r", 4.5);
|
||||
node.append( 'circle' )
|
||||
.attr( 'r', 4.5 );
|
||||
|
||||
node.append("text")
|
||||
.attr("dx", function(d) { return d.x < 180 ? 8 : -8; })
|
||||
.attr("dy", ".31em")
|
||||
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
|
||||
.attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; })
|
||||
.text(function(d) { return d.name; });
|
||||
//*/
|
||||
node.append( 'text' )
|
||||
.attr( 'dx', function(d) { return d.x < 180 ? 8 : -8; } )
|
||||
.attr( 'dy', '.31em' )
|
||||
.attr( 'text-anchor', function(d) { return d.x < 180 ? 'start' : 'end'; } )
|
||||
.attr( 'transform', function(d) { return d.x < 180 ? null : 'rotate(180)'; } )
|
||||
.attr( 'data-href', function( d ) { return d.name; } )
|
||||
.text( helper_node_text );
|
||||
|
||||
$( 'text[data-href*="//"]', graph_element )
|
||||
.die( 'click' )
|
||||
.live
|
||||
(
|
||||
'click',
|
||||
function()
|
||||
{
|
||||
location.href = $( this ).data( 'href' );
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
var init_graph = function( graph_element )
|
||||
var prepare_graph = function( graph_element, callback )
|
||||
{
|
||||
$.ajax
|
||||
(
|
||||
{
|
||||
url : app.config.solr_path + '/zookeeper?wt=json&path=%2Flive_nodes',
|
||||
dataType : 'json',
|
||||
success : function( response, text_status, xhr )
|
||||
{
|
||||
var live_nodes = {};
|
||||
for( var c in response.tree[0].children )
|
||||
{
|
||||
live_nodes[response.tree[0].children[c].data.title] = true;
|
||||
}
|
||||
|
||||
$.ajax
|
||||
(
|
||||
{
|
||||
|
@ -254,6 +362,7 @@ var init_graph = function( graph_element )
|
|||
var state = null;
|
||||
eval( 'state = ' + response.znode.data + ';' );
|
||||
|
||||
var leaf_count = 0;
|
||||
var collections = [];
|
||||
for( var c in state )
|
||||
{
|
||||
|
@ -263,20 +372,44 @@ var init_graph = function( graph_element )
|
|||
var nodes = [];
|
||||
for( var n in state[c][s] )
|
||||
{
|
||||
leaf_count++;
|
||||
|
||||
var uri = state[c][s][n].base_url;
|
||||
var parts = uri.match( /^(\w+:)\/\/(([\w\d\.-]+)(:(\d+))?)(.+)$/ );
|
||||
var uri_parts = {
|
||||
protocol: parts[1],
|
||||
host: parts[2],
|
||||
hostname: parts[3],
|
||||
port: parseInt( parts[5] || 80, 10 ),
|
||||
pathname: parts[6]
|
||||
};
|
||||
|
||||
helper_data.protocol.push( uri_parts.protocol );
|
||||
helper_data.host.push( uri_parts.host );
|
||||
helper_data.hostname.push( uri_parts.hostname );
|
||||
helper_data.port.push( uri_parts.port );
|
||||
helper_data.pathname.push( uri_parts.pathname );
|
||||
|
||||
var status = state[c][s][n].state;
|
||||
|
||||
if( !live_nodes[state[c][s][n].node_name] )
|
||||
{
|
||||
status = 'gone';
|
||||
}
|
||||
|
||||
var node = {
|
||||
id: state[c][s][n].node_name,
|
||||
name: state[c][s][n].base_url,
|
||||
name: uri,
|
||||
data: {
|
||||
type : 'node',
|
||||
state : state[c][s][n].state,
|
||||
leader : 'true' === state[c][s][n].leader
|
||||
state : status,
|
||||
leader : 'true' === state[c][s][n].leader,
|
||||
uri : uri_parts
|
||||
}
|
||||
};
|
||||
nodes.push( node );
|
||||
}
|
||||
|
||||
var shard = {
|
||||
id: s,
|
||||
name: s,
|
||||
data: {
|
||||
type : 'shard',
|
||||
|
@ -287,7 +420,6 @@ var init_graph = function( graph_element )
|
|||
}
|
||||
|
||||
var collection = {
|
||||
id: c,
|
||||
name: c,
|
||||
data: {
|
||||
type : 'collection',
|
||||
|
@ -298,7 +430,23 @@ var init_graph = function( graph_element )
|
|||
}
|
||||
|
||||
var graph_data = collections.shift();
|
||||
generate_graph( graph_element, graph_data );
|
||||
|
||||
helper_data.protocol = $.unique( helper_data.protocol );
|
||||
helper_data.host = $.unique( helper_data.host );
|
||||
helper_data.hostname = $.unique( helper_data.hostname );
|
||||
helper_data.port = $.unique( helper_data.port );
|
||||
helper_data.pathname = $.unique( helper_data.pathname );
|
||||
|
||||
callback( graph_element, graph_data, leaf_count );
|
||||
},
|
||||
error : function( xhr, text_status, error_thrown)
|
||||
{
|
||||
},
|
||||
complete : function( xhr, text_status )
|
||||
{
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
error : function( xhr, text_status, error_thrown)
|
||||
{
|
||||
|
@ -311,6 +459,30 @@ var init_graph = function( graph_element )
|
|||
|
||||
};
|
||||
|
||||
var init_graph = function( graph_element )
|
||||
{
|
||||
prepare_graph
|
||||
(
|
||||
graph_element,
|
||||
function( graph_element, graph_data, leaf_count )
|
||||
{
|
||||
generate_graph( graph_element, graph_data, leaf_count );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var init_rgraph = function( graph_element )
|
||||
{
|
||||
prepare_graph
|
||||
(
|
||||
graph_element,
|
||||
function( graph_element, graph_data, leaf_count )
|
||||
{
|
||||
generate_rgraph( graph_element, graph_data, leaf_count );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var init_tree = function( tree_element )
|
||||
{
|
||||
$.ajax
|
||||
|
@ -531,6 +703,18 @@ sammy.get
|
|||
}
|
||||
);
|
||||
|
||||
$( '.rgraph', navigation_element )
|
||||
.die( 'activate' )
|
||||
.live
|
||||
(
|
||||
'activate',
|
||||
function( event )
|
||||
{
|
||||
$( this ).addClass( 'current' );
|
||||
init_rgraph( $( '#graph-content', cloud_element ) );
|
||||
}
|
||||
);
|
||||
|
||||
$( 'a[href="' + context.path + '"]', navigation_element )
|
||||
.trigger( 'activate' );
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ limitations under the License.
|
|||
|
||||
<ul>
|
||||
<li class="tree"><a href="#/~cloud">Tree</a></li>
|
||||
<li class="graph"><a href="#/~cloud?view=graph">Graph</a></li>
|
||||
<li class="rgraph"><a href="#/~cloud?view=rgraph">Graph (Radial)</a></li>
|
||||
<li class="dump"><a href="#/~cloud">Dump</a></li>
|
||||
</ul>
|
||||
|
||||
|
|
Loading…
Reference in New Issue