Repository: eagle Updated Branches: refs/heads/master 4ff4d628f -> 01553a346
[EAGLE-953] Host-level Overview Heatmap Diagram for Topology Monitoring https://issues.apache.org/jira/browse/EAGLE-953 Author: koone <[email protected]> Closes #907 from koone/heatmap. Project: http://git-wip-us.apache.org/repos/asf/eagle/repo Commit: http://git-wip-us.apache.org/repos/asf/eagle/commit/01553a34 Tree: http://git-wip-us.apache.org/repos/asf/eagle/tree/01553a34 Diff: http://git-wip-us.apache.org/repos/asf/eagle/diff/01553a34 Branch: refs/heads/master Commit: 01553a34639423621b534bc9837dea4cf4c71b4b Parents: 4ff4d62 Author: koone <[email protected]> Authored: Thu Apr 13 06:20:05 2017 +0000 Committer: r7raul1984 <[email protected]> Committed: Thu Apr 13 06:20:05 2017 +0000 ---------------------------------------------------------------------- .../apps/hbase/ctrls/backupMasterListCtrl.js | 124 ++++++++++++++++++- .../app/apps/hbase/ctrls/regionListCtrl.js | 124 ++++++++++++++++++- .../src/main/webapp/app/apps/hbase/index.js | 18 ++- .../apps/hbase/partials/backupMasterList.html | 85 ++++++++----- .../apps/hbase/partials/region/regionList.html | 88 ++++++++----- .../app/apps/hdfs/ctrl/datanodeListCtrl.js | 118 +++++++++++++++++- .../app/apps/hdfs/ctrl/namenodeListCtrl.js | 120 +++++++++++++++++- .../app/apps/hdfs/partials/datanodeList.html | 88 ++++++++----- .../app/apps/hdfs/partials/namenodeList.html | 88 ++++++++----- .../webapp/app/apps/hdfs/partials/overview.html | 4 +- 10 files changed, 711 insertions(+), 146 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/eagle/blob/01553a34/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/backupMasterListCtrl.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/backupMasterListCtrl.js b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/backupMasterListCtrl.js index ca6c47e..2330885 100644 --- a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/backupMasterListCtrl.js +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/backupMasterListCtrl.js @@ -7,7 +7,7 @@ * "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 + * 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, @@ -30,6 +30,128 @@ $scope.site = $wrapState.param.siteId; $scope.searchPathList = [["tags", "hostname"], ["tags", "rack"], ["tags", "site"], ["status"]]; $scope.backupMasterList = METRIC.hbaseMaster($scope.site, "standby", 1000); + + $scope.masterAll = METRIC.hbaseMaster($scope.site); + + + function getCommonHeatMapSeries(name, data) { + return { + name: name, + type: 'heatmap', + data: data, + label: { + normal: { + show: true, + formatter: function (point) { + if(point.data) { + return point.data[3]; + } + return ""; + } + } + }, + itemStyle: { + normal: { + borderColor: "#FFF" + }, + emphasis: { + shadowBlur: 10, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + }; + } + + function getCommonHeatMapOption() { + return { + animation: false, + tooltip: { + trigger: 'item' + }, + xAxis: { + show: false, + data: [0,-1,-2,-3,-4], + splitArea: {show: true} + }, + yAxis: [{ + show: false, + splitArea: {show: true}, + axisTick: {show: false} + }], + grid: { + left: "1%", + right: "1%", + top: "60", + bottom: "60" + }, + visualMap: { + categories: ['active', 'standby'], + calculable: true, + orient: 'horizontal', + right: "2%", + inRange: { + color: ['#00a65a', '#dd4b39'] + } + } + }; + } + + + // region server heatmap chart + $scope.masterAll._promise.then(function () { + var master_status = []; + var master_status_category = []; + var x = -1; + var y = 0; + var split = 5; + $.each($scope.masterAll, + /** + * @param {number} i + * @param {RegionServer} master + */ + function (i, master) { + if(x === split){ + x = 0; + y = y - 1; + }else{ + x = x +1; + } + master_status.push([x, y, 0, master.tags.hostname, master.tags.rack, master.status || "-"]) + }); + for(var i = 0;i < split; i++){ + master_status_category.push(i); + } + $scope.healthStatusSeries = [getCommonHeatMapSeries("Health", master_status)]; + console.log($scope.healthStatusSeries); + $scope.healthStatusOption = getHealthHeatMapOption(); + console.log($scope.healthStatusOption); + $scope.healthStatusCategory = master_status_category; + $scope.heatmapHeight = { + 'height': getHeight(y) + }; + + function getHeight(x){ + return (Math.abs(x-1)*30 + 140) + "px" + } + + function getHealthHeatMapOption() { + var option = getCommonHeatMapOption(); + return common.merge(option, { + tooltip: { + formatter: function (point) { + if(point.data) { + return point.data[3] + '<br/>' + + 'status: <span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + point.color + '"></span> ' + point.data[5] + '<br/>' + + 'rack: ' + point.data[4] + '<br/>'; + } + return ""; + } + } + }); + } + + }); + }); }); })(); http://git-wip-us.apache.org/repos/asf/eagle/blob/01553a34/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionListCtrl.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionListCtrl.js b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionListCtrl.js index 6fc9ab0..401ef15 100644 --- a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionListCtrl.js +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionListCtrl.js @@ -7,7 +7,7 @@ * "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 + * 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, @@ -33,6 +33,128 @@ $scope.status = $wrapState.param.status; $scope.searchPathList = [["tags", "hostname"], ["tags", "rack"], ["tags", "site"], ["status"]]; $scope.regionserverList = METRIC.regionserverList($scope.site, $scope.status); + $scope.regionserverAll = METRIC.regionserverList($scope.site); + + + function getCommonHeatMapSeries(name, data) { + return { + name: name, + type: 'heatmap', + data: data, + label: { + normal: { + show: true, + formatter: function (point) { + if(point.data) { + return point.data[3]; + } + return ""; + } + } + }, + itemStyle: { + normal: { + borderColor: "#FFF" + }, + emphasis: { + shadowBlur: 10, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + }; + } + + function getCommonHeatMapOption() { + return { + animation: false, + tooltip: { + trigger: 'item' + }, + grid: { + left: "1%", + right: "1%", + top: "60", + bottom: "60" + }, + xAxis: { + show: false, + splitArea: {show: true} + }, + yAxis: [{ + show: false, + splitArea: {show: true}, + axisTick: {show: false} + }], + visualMap: { + categories: ['live', 'dead'], + calculable: true, + orient: 'horizontal', + right: "2%", + inRange: { + color: ['#00a65a', '#dd4b39'] + } + } + }; + } + + + // region server heatmap chart + $scope.regionserverAll._promise.then(function () { + var regionServer_status = []; + var regionServer_status_category = []; + var regionServer_level = []; + var x = -1; + var y = 0; + var split = 5; + $.each($scope.regionserverAll, + /** + * @param {number} i + * @param {RegionServer} regionServer + */ + function (i, regionServer) { + if(x === split){ + x = 0; + y = y - 1; + }else{ + x = x +1; + } + regionServer_status.push([x, y, 0, regionServer.tags.hostname, regionServer.tags.rack, regionServer.usedHeapMB, regionServer.maxHeapMB, regionServer.status || "-"]); + }); + + for(var i = 0;i < split; i++){ + regionServer_status_category.push(i); + } + $scope.healthStatusSeries = [getCommonHeatMapSeries("Health", regionServer_status)]; + $scope.healthStatusOption = getHealthHeatMapOption(); + $scope.healthStatusCategory = regionServer_status_category; + $scope.heatmapHeight = { + 'height': getHeight(y) + }; + + function getHeight(x){ + return (Math.abs(x-1)*30 + 140) + "px" + } + + function getHealthHeatMapOption() { + var option = getCommonHeatMapOption(); + return common.merge(option, { + tooltip: { + formatter: function (point) { + if(point.data) { + return point.data[3] + '<br/>' + + 'status: <span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + point.color + '"></span> ' + point.data[7] + '<br/>' + + 'rack: ' + point.data[4] + '<br/>' + + 'heap used: ' + point.data[5] + '/' + point.data[6] + ' MB<br/>'; + } + return ""; + } + } + }); + } + + }); }); + + }); })(); http://git-wip-us.apache.org/repos/asf/eagle/blob/01553a34/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.js b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.js index 8e4ea46..157cded 100644 --- a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.js +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.js @@ -283,11 +283,19 @@ }; METRIC.hbaseMaster = function (siteId, status, limit) { - var condition = { - site: siteId, - role: "hmaster", - status: status - }; + var condition = {}; + if(typeof status === 'undefined') { + condition = { + site: siteId, + role: "hmaster" + }; + } else { + condition = { + site: siteId, + role: "hmaster", + status: status + }; + } return METRIC.hbasehostStatus(condition, limit); }; http://git-wip-us.apache.org/repos/asf/eagle/blob/01553a34/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/backupMasterList.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/backupMasterList.html b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/backupMasterList.html index 13e20c9..e35aae3 100644 --- a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/backupMasterList.html +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/backupMasterList.html @@ -15,38 +15,57 @@ See the License for the specific language governing permissions and limitations under the License. --> -<div class="box box-primary"> - <div class="box-header with-border"> - <h3 class="box-title"> - <span ng-show="!backupMasterList._done || isSorting" class="fa fa-refresh fa-spin no-animate"></span> - </h3> - </div> - <div class="box-body"> - <div id="backupMasterList" sort-table="backupMasterList" is-sorting="isSorting" - search-path-list="searchPathList" - scope="tableScope"> - <table class="table table-bordered"> - <thead> - <tr> - <th sortpath="tags.hostname">Master</th> - <th sortpath="tags.rack">Rack</th> - <th sortpath="tags.site">SiteId</th> - <th sortpath="status">Status</th> - </tr> - </thead> - <tbody> - <tr ng-repeat="item in backupMasterList"> - <td> - <a ui-sref="masterDetail({siteId: site, hostname: item.tags.hostname})">{{item.tags.hostname}}</a> - </td> - <td>{{item.tags.rack}}</td> - <td>{{item.tags.site}}</td> - <td> - <span>{{item.status}}</span> - </td> - </tr> - </tbody> - </table> +<div class="nav-tabs-custom" style="cursor: move;"> + <ul class="nav nav-tabs pull-right ui-sortable-handle"> + <li><a href="#heatmap" data-toggle="tab" aria-expanded="false" ng-click="healthHeatMap.resize()">HeatMap</a></li> + <li class="active"><a href="#list" data-toggle="tab" aria-expanded="true">List</a></li> + </ul> + + <div class="tab-content no-padding keepContent"> + <div class="box box-primary no-margin tab-pane fade in active" id="list"> + <div class="box-body"> + <div id="backupMasterList" sort-table="backupMasterList" is-sorting="isSorting" + search-path-list="searchPathList" + scope="tableScope"> + <table class="table table-bordered"> + <thead> + <tr> + <th sortpath="tags.hostname">Master</th> + <th sortpath="tags.rack">Rack</th> + <th sortpath="tags.site">SiteId</th> + <th sortpath="status">Status</th> + </tr> + </thead> + <tbody> + <tr ng-repeat="item in backupMasterList"> + <td> + <a ui-sref="masterDetail({siteId: site, hostname: item.tags.hostname})">{{item.tags.hostname}}</a> + </td> + <td>{{item.tags.rack}}</td> + <td>{{item.tags.site}}</td> + <td> + <span>{{item.status}}</span> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + + + <!--region server health chart--> + <div class="box box-primary no-margin tab-pane fade" id="heatmap"> + <div class="box-body"> + <div class="hadoopMetric-chart"> + <div chart="healthHeatMap" ng-style="heatmapHeight" series="healthStatusSeries" category="healthStatusCategory" option="healthStatusOption"></div> + <div ng-if="(healthStatusSeries || []).length === 0" class="overlay"> + <i class="fa fa-refresh fa-spin"></i> + </div> + </div> + </div> </div> - </div> + + </div> + </div> http://git-wip-us.apache.org/repos/asf/eagle/blob/01553a34/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionList.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionList.html b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionList.html index d1a7440..dd78c3b 100644 --- a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionList.html +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionList.html @@ -15,39 +15,59 @@ See the License for the specific language governing permissions and limitations under the License. --> -<div class="box box-primary"> - <div class="box-header with-border"> - <h3 class="box-title"> - <span ng-show="!regionserverList._done || isSorting" class="fa fa-refresh fa-spin no-animate"></span> - </h3> - </div> - <div class="box-body"> - <div id="regionserverList" sort-table="regionserverList" is-sorting="isSorting" - search-path-list="searchPathList" - scope="tableScope"> - <table class="table table-bordered"> - <thead> - <tr> - <th sortpath="tags.hostname">RegionServer</th> - <th sortpath="tags.rack">Rack</th> - <th sortpath="tags.site">SiteId</th> - <th sortpath="status">Status</th> - </tr> - </thead> - <tbody> - <tr ng-repeat="item in regionserverList"> - <td> - <a ui-sref="regionDetail({siteId: site, hostname: item.tags.hostname})">{{item.tags.hostname}}</a> - </td> - <td>{{item.tags.rack}}</td> - <td>{{item.tags.site}}</td> - <td> - <span ng-if="item.status===live" class="label label-success">Healthy</span> - <span ng-if="item.status===dead" class="label label-danger">UnHealthy</span> - </td> - </tr> - </tbody> - </table> +<div class="nav-tabs-custom" style="cursor: move;"> + <ul class="nav nav-tabs pull-right ui-sortable-handle"> + <li><a href="#heatmap" data-toggle="tab" aria-expanded="false" ng-click="healthHeatMap.resize()">HeatMap</a></li> + <li class="active"><a href="#list" data-toggle="tab" aria-expanded="true">List</a></li> + </ul> + + <div class="tab-content no-padding keepContent"> + <div class="box box-primary no-margin tab-pane fade in active" id="list"> + <div class="box-body"> + <div id="regionserverList" sort-table="regionserverList" is-sorting="isSorting" + search-path-list="searchPathList" + scope="tableScope"> + <table class="table table-bordered"> + <thead> + <tr> + <th sortpath="tags.hostname">RegionServer</th> + <th sortpath="tags.rack">Rack</th> + <th sortpath="tags.site">SiteId</th> + <th sortpath="status">Status</th> + </tr> + </thead> + <tbody> + <tr ng-repeat="item in regionserverList"> + <td> + <a ui-sref="regionDetail({siteId: site, hostname: item.tags.hostname})">{{item.tags.hostname}}</a> + </td> + <td>{{item.tags.rack}}</td> + <td>{{item.tags.site}}</td> + <td> + <span ng-if="item.status===live" class="label label-success">Healthy</span> + <span ng-if="item.status===dead" class="label label-danger">UnHealthy</span> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + + + <!--region server health chart--> + <div class="box box-primary no-margin tab-pane fade" id="heatmap"> + <div class="box-body"> + <div class="hadoopMetric-chart"> + <div chart="healthHeatMap" ng-style="heatmapHeight" series="healthStatusSeries" category="healthStatusCategory" option="healthStatusOption"></div> + <div ng-if="(healthStatusSeries || []).length === 0" class="overlay"> + <i class="fa fa-refresh fa-spin"></i> + </div> + </div> + </div> </div> - </div> + + </div> + </div> + http://git-wip-us.apache.org/repos/asf/eagle/blob/01553a34/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/datanodeListCtrl.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/datanodeListCtrl.js b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/datanodeListCtrl.js index 78ea7e1..7664b7c 100644 --- a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/datanodeListCtrl.js +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/datanodeListCtrl.js @@ -7,7 +7,7 @@ * "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 + * 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, @@ -35,6 +35,122 @@ $scope.datanodeList = (typeof $scope.status === 'undefined') ? HDFSMETRIC.getListByRoleName("HdfsServiceInstance", "datanode", $scope.site) : HDFSMETRIC.getHadoopHostByStatusAndRole("HdfsServiceInstance", $scope.site, $scope.status, "datanode"); + $scope.datanodeAll = HDFSMETRIC.getListByRoleName("HdfsServiceInstance", "datanode", $scope.site); + + + function getCommonHeatMapSeries(name, data) { + return { + name: name, + type: 'heatmap', + data: data, + label: { + normal: { + show: true, + formatter: function (point) { + if(point.data) { + return point.data[3]; + } + return ""; + } + } + }, + itemStyle: { + normal: { + borderColor: "#FFF" + }, + emphasis: { + shadowBlur: 10, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + }; + } + + function getCommonHeatMapOption() { + return { + animation: false, + tooltip: { + trigger: 'item' + }, + xAxis: { + show: false, + splitArea: {show: true} + }, + yAxis: [{ + show: false, + splitArea: {show: true}, + axisTick: {show: false} + }], + grid: { + left: "1%", + right: "1%", + top: "60", + bottom: "60" + }, + visualMap: { + categories: ['live', 'dead'], + calculable: true, + orient: 'horizontal', + right: "2%", + inRange: { + color: ['#00a65a', '#dd4b39'] + } + } + }; + } + + + // region server heatmap chart + $scope.datanodeAll._promise.then(function () { + var datanode_status = []; + var datanode_status_category = []; + var x = -1; + var y = 0; + var split = 5; + $.each($scope.datanodeAll, + /** + * @param {number} i + * @param {RegionServer} datanode + */ + function (i, datanode) { + if(x === split){ + x = 0; + y = y - 1; + }else{ + x = x +1; + } + datanode_status.push([x, y, 0, datanode.tags.hostname, datanode.tags.rack, datanode.status || "-"]) + }); + for(var i = 0;i < split; i++){ + datanode_status_category.push(i); + } + $scope.healthStatusSeries = [getCommonHeatMapSeries("Health", datanode_status)]; + $scope.healthStatusOption = getHealthHeatMapOption(); + $scope.healthStatusCategory = datanode_status_category; + $scope.heatmapHeight = { + 'height': getHeight(y) + }; + function getHeight(x){ + return (Math.abs(x-1)*30 + 140) + "px" + } + + function getHealthHeatMapOption() { + var option = getCommonHeatMapOption(); + return common.merge(option, { + tooltip: { + formatter: function (point) { + if(point.data) { + return point.data[3] + '<br/>' + + 'status: <span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + point.color + '"></span> ' + point.data[5] + '<br/>' + + 'rack: ' + point.data[4] + '<br/>'; + } + return ""; + } + } + }); + } + + }); }); }); })(); http://git-wip-us.apache.org/repos/asf/eagle/blob/01553a34/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/namenodeListCtrl.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/namenodeListCtrl.js b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/namenodeListCtrl.js index 8424b8e..d0d41bf 100644 --- a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/namenodeListCtrl.js +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/namenodeListCtrl.js @@ -7,7 +7,7 @@ * "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 + * 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, @@ -32,6 +32,124 @@ $scope.searchPathList = [["tags", "hostname"], ["tags", "rack"], ["tags", "site"], ["status"]]; $scope.namenodeList = (typeof $scope.status === 'undefined') ? HDFSMETRIC.getListByRoleName("HdfsServiceInstance", "namenode", $scope.site) : HDFSMETRIC.getHadoopHostByStatusAndRole("HdfsServiceInstance", $scope.site, $scope.status, "namenode"); + + $scope.namenodeAll = HDFSMETRIC.getListByRoleName("HdfsServiceInstance", "namenode", $scope.site); + + + function getCommonHeatMapSeries(name, data) { + return { + name: name, + type: 'heatmap', + data: data, + label: { + normal: { + show: true, + formatter: function (point) { + if(point.data) { + return point.data[3]; + } + return ""; + } + } + }, + itemStyle: { + normal: { + borderColor: "#FFF" + }, + emphasis: { + shadowBlur: 10, + shadowColor: 'rgba(0, 0, 0, 0.5)' + } + } + }; + } + + function getCommonHeatMapOption() { + return { + animation: false, + tooltip: { + trigger: 'item' + }, + xAxis: { + show: false, + splitArea: {show: true} + }, + yAxis: [{ + show: false, + splitArea: {show: true}, + axisTick: {show: false} + }], + grid: { + left: "1%", + right: "1%", + top: "60", + bottom: "60" + }, + visualMap: { + categories: ['active', 'standby'], + calculable: true, + orient: 'horizontal', + right: "2%", + inRange: { + color: ['#00a65a', '#dd4b39'] + } + } + }; + } + + + // region server heatmap chart + $scope.namenodeAll._promise.then(function () { + var namenode_status = []; + var namenode_status_category = []; + var x = -1; + var y = 0; + var split = 5; + $.each($scope.namenodeAll, + /** + * @param {number} i + * @param {RegionServer} namenode + */ + function (i, namenode) { + if(x === split){ + x = 0; + y = y - 1; + }else{ + x = x +1; + } + namenode_status.push([x, y, 0, namenode.tags.hostname, namenode.tags.rack, namenode.usedCapacityTB, namenode.status || "-"]) + }); + for(var i = 0;i < split; i++){ + namenode_status_category.push(i); + } + $scope.healthStatusSeries = [getCommonHeatMapSeries("Health", namenode_status)]; + $scope.healthStatusOption = getHealthHeatMapOption(); + $scope.healthStatusCategory = namenode_status_category; + $scope.heatmapHeight = { + 'height': getHeight(y) + }; + function getHeight(x){ + return (Math.abs(x-1)*30 + 140) + "px" + } + + function getHealthHeatMapOption() { + var option = getCommonHeatMapOption(); + return common.merge(option, { + tooltip: { + formatter: function (point) { + if(point.data) { + return point.data[3] + '<br/>' + + 'status: <span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + point.color + '"></span> ' + point.data[6] + '<br/>' + + 'rack: ' + point.data[4] + '<br/>' + + 'usedCapacity: ' + point.data[5] + ' TB<br/>'; + } + return ""; + } + } + }); + } + + }); }); }); })(); http://git-wip-us.apache.org/repos/asf/eagle/blob/01553a34/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/datanodeList.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/datanodeList.html b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/datanodeList.html index b76d44d..a53251e 100644 --- a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/datanodeList.html +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/datanodeList.html @@ -15,39 +15,59 @@ See the License for the specific language governing permissions and limitations under the License. --> -<div class="box box-primary"> - <div class="box-header with-border"> - <h3 class="box-title"> - <span ng-show="!datanodeList._done || isSorting" class="fa fa-refresh fa-spin no-animate"></span> - </h3> - </div> - <div class="box-body"> - <div id="datanodeList" sort-table="datanodeList" is-sorting="isSorting" - search-path-list="searchPathList" - scope="tableScope"> - <table class="table table-bordered"> - <thead> - <tr> - <th sortpath="tags.hostname">Datanode</th> - <th sortpath="tags.rack">Rack</th> - <th sortpath="tags.site">SiteId</th> - <th sortpath="status">Status</th> - </tr> - </thead> - <tbody> - <tr ng-repeat="item in datanodeList"> - <td> - <a ui-sref="datanodeDetail({siteId: site, hostname: item.tags.hostname})" target="_blank">{{item.tags.hostname}}</a> - </td> - <td>{{item.tags.rack}}</td> - <td>{{item.tags.site}}</td> - <td> - <span ng-if="item.status===live" class="label label-success">Healthy</span> - <span ng-if="item.status===dead" class="label label-danger">UnHealthy</span> - </td> - </tr> - </tbody> - </table> + +<div class="nav-tabs-custom" style="cursor: move;"> + <ul class="nav nav-tabs pull-right ui-sortable-handle"> + <li><a href="#heatmap" data-toggle="tab" aria-expanded="false" ng-click="healthHeatMap.resize()">HeatMap</a></li> + <li class="active"><a href="#list" data-toggle="tab" aria-expanded="true">List</a></li> + </ul> + + <div class="tab-content no-padding keepContent"> + <div class="box box-primary no-margin tab-pane fade in active" id="list"> + <div class="box-body"> + <div id="datanodeList" sort-table="datanodeList" is-sorting="isSorting" + search-path-list="searchPathList" + scope="tableScope"> + <table class="table table-bordered"> + <thead> + <tr> + <th sortpath="tags.hostname">Datanode</th> + <th sortpath="tags.rack">Rack</th> + <th sortpath="tags.site">SiteId</th> + <th sortpath="status">Status</th> + </tr> + </thead> + <tbody> + <tr ng-repeat="item in datanodeList"> + <td> + <a ui-sref="datanodeDetail({siteId: site, hostname: item.tags.hostname})" target="_blank">{{item.tags.hostname}}</a> + </td> + <td>{{item.tags.rack}}</td> + <td>{{item.tags.site}}</td> + <td> + <span ng-if="item.status===live" class="label label-success">Healthy</span> + <span ng-if="item.status===dead" class="label label-danger">UnHealthy</span> + </td> + </tr> + </tbody> + </table> + </div> + </div> </div> - </div> + + + <!--region server health chart--> + <div class="box box-primary no-margin tab-pane fade" id="heatmap"> + <div class="box-body"> + <div class="hadoopMetric-chart"> + <div chart="healthHeatMap" ng-style="heatmapHeight" series="healthStatusSeries" category="healthStatusCategory" option="healthStatusOption"></div> + <div ng-if="(healthStatusSeries || []).length === 0" class="overlay"> + <i class="fa fa-refresh fa-spin"></i> + </div> + </div> + </div> + </div> + + </div> + </div> http://git-wip-us.apache.org/repos/asf/eagle/blob/01553a34/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/namenodeList.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/namenodeList.html b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/namenodeList.html index d10aa0b..d9bab1a 100644 --- a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/namenodeList.html +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/namenodeList.html @@ -15,38 +15,58 @@ See the License for the specific language governing permissions and limitations under the License. --> -<div class="box box-primary"> - <div class="box-header with-border"> - <h3 class="box-title"> - <span ng-show="!namenodeList._done || isSorting" class="fa fa-refresh fa-spin no-animate"></span> - </h3> - </div> - <div class="box-body"> - <div id="namenodeList" sort-table="namenodeList" is-sorting="isSorting" - search-path-list="searchPathList" - scope="tableScope"> - <table class="table table-bordered"> - <thead> - <tr> - <th sortpath="tags.hostname">Namenode</th> - <th sortpath="tags.rack">Rack</th> - <th sortpath="tags.site">SiteId</th> - <th sortpath="status">Status</th> - </tr> - </thead> - <tbody> - <tr ng-repeat="item in namenodeList"> - <td> - <a ui-sref="namenodeDetail({siteId: site, hostname: item.tags.hostname})" target="_blank">{{item.tags.hostname}}</a> - </td> - <td>{{item.tags.rack}}</td> - <td>{{item.tags.site}}</td> - <td> - <span>{{item.status}}</span> - </td> - </tr> - </tbody> - </table> + +<div class="nav-tabs-custom" style="cursor: move;"> + <ul class="nav nav-tabs pull-right ui-sortable-handle"> + <li><a href="#heatmap" data-toggle="tab" aria-expanded="false" ng-click="healthHeatMap.resize()">HeatMap</a></li> + <li class="active"><a href="#list" data-toggle="tab" aria-expanded="true">List</a></li> + </ul> + + <div class="tab-content no-padding keepContent"> + <div class="box box-primary no-margin tab-pane fade in active" id="list"> + <div class="box-body"> + <div id="namenodeList" sort-table="namenodeList" is-sorting="isSorting" + search-path-list="searchPathList" + scope="tableScope"> + <table class="table table-bordered"> + <thead> + <tr> + <th sortpath="tags.hostname">Namenode</th> + <th sortpath="tags.rack">Rack</th> + <th sortpath="tags.site">SiteId</th> + <th sortpath="status">Status</th> + </tr> + </thead> + <tbody> + <tr ng-repeat="item in namenodeList"> + <td> + <a ui-sref="namenodeDetail({siteId: site, hostname: item.tags.hostname})" target="_blank">{{item.tags.hostname}}</a> + </td> + <td>{{item.tags.rack}}</td> + <td>{{item.tags.site}}</td> + <td> + <span>{{item.status}}</span> + </td> + </tr> + </tbody> + </table> + </div> + </div> </div> - </div> -</div> + + + <!--region server health chart--> + <div class="box box-primary no-margin tab-pane fade" id="heatmap"> + <div class="box-body"> + <div class="hadoopMetric-chart"> + <div chart="healthHeatMap" ng-style="heatmapHeight" series="healthStatusSeries" category="healthStatusCategory" option="healthStatusOption"></div> + <div ng-if="(healthStatusSeries || []).length === 0" class="overlay"> + <i class="fa fa-refresh fa-spin"></i> + </div> + </div> + </div> + </div> + + </div> + +</div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/eagle/blob/01553a34/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/overview.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/overview.html b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/overview.html index 7a6d9ad..52f8e92 100644 --- a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/overview.html +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/overview.html @@ -28,7 +28,7 @@ <tr> <td width="5%"> <span ng-show="!namenodeactivenum">0</span> - <span ng-show="namenodeactivenum!==-1"><a ui-sref="namenodeList({siteId: site, status: 'active'})" target="_blank">{{namenodeactivenum}}</a></span> + <span ng-show="namenodeactivenum!==-1"><a ui-sref="namenodeList({siteId: site, status: 'active'})">{{namenodeactivenum}}</a></span> <span ng-show="namenodeactivenum===-1">N/A</span> </td> <th width="30%">Active Namenode</th> @@ -46,7 +46,7 @@ </tr> <tr> <td> - <span ng-show="namenodestandbynum!==-1"><a ui-sref="namenodeList({siteId: site, status: 'standby'})" target="_blank">{{namenodestandbynum}}</a></span> + <span ng-show="namenodestandbynum!==-1"><a ui-sref="namenodeList({siteId: site, status: 'standby'})">{{namenodestandbynum}}</a></span> <span ng-show="!namenodestandbynum">0</span> <span ng-show="namenodestandbynum===-1">N/A</span> </td>
