Repository: eagle Updated Branches: refs/heads/master d2fee6e6f -> 257a3517b
[EAGLE-845] JMX Dashboard EAGLE-845 JMX Dashboard - Add HBase master metric dashboard. - Add HBase RegionServer metric dashboard. - Integrate hbase metric to basic panel. https://issues.apache.org/jira/browse/EAGLE-845 Author: chitin <[email protected]> Author: r7raul1984 <[email protected]> Closes #753 from chitin/hbase-jmx-metric. Project: http://git-wip-us.apache.org/repos/asf/eagle/repo Commit: http://git-wip-us.apache.org/repos/asf/eagle/commit/257a3517 Tree: http://git-wip-us.apache.org/repos/asf/eagle/tree/257a3517 Diff: http://git-wip-us.apache.org/repos/asf/eagle/diff/257a3517 Branch: refs/heads/master Commit: 257a3517bf0b191dfe931c21232810f65cfc5a63 Parents: d2fee6e Author: chitin <[email protected]> Authored: Fri Jan 6 11:25:44 2017 +0800 Committer: zombieJ <[email protected]> Committed: Fri Jan 6 11:25:44 2017 +0800 ---------------------------------------------------------------------- ...le.metric.HadoopMetricMonitorAppProdiver.xml | 16 ++ .../webapp/app/apps/hadoop_metric/config.json | 68 +++++ .../app/apps/hadoop_metric/ctrls/overview.js | 172 +++++++++--- .../hadoop_metric/ctrls/regionDetailCtrl.js | 164 ++++++++++++ .../apps/hadoop_metric/ctrls/regionListCtrl.js | 56 ++++ .../main/webapp/app/apps/hadoop_metric/index.js | 264 ++++++++++++++++++- .../apps/hadoop_metric/partials/overview.html | 36 ++- .../partials/region/regionDetail.html | 105 ++++++++ .../partials/region/regionList.html | 53 ++++ .../app/apps/hadoop_metric/style/index.css | 7 +- .../hadoop_metric/widgets/availabilityChart.js | 2 +- 11 files changed, 897 insertions(+), 46 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/resources/META-INF/providers/org.apache.eagle.metric.HadoopMetricMonitorAppProdiver.xml ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/resources/META-INF/providers/org.apache.eagle.metric.HadoopMetricMonitorAppProdiver.xml b/eagle-hadoop-metric/src/main/resources/META-INF/providers/org.apache.eagle.metric.HadoopMetricMonitorAppProdiver.xml index 9a32eda..7b7c273 100644 --- a/eagle-hadoop-metric/src/main/resources/META-INF/providers/org.apache.eagle.metric.HadoopMetricMonitorAppProdiver.xml +++ b/eagle-hadoop-metric/src/main/resources/META-INF/providers/org.apache.eagle.metric.HadoopMetricMonitorAppProdiver.xml @@ -20,6 +20,12 @@ <type>HADOOP_METRIC_MONITOR</type> <name>Hadoop Metrics Monitor</name> <viewPath>/apps/hadoop_metric</viewPath> + <dependencies> + <dependency> + <type>TOPOLOGY_HEALTH_CHECK_APP</type> + <required>true</required> + </dependency> + </dependencies> <configuration> <!-- data fromStream configurations --> <property> @@ -84,6 +90,16 @@ <description>Kafka Transaction Status Update MS</description> <required>false</required> </property> + <property> + <name>service.host</name> + <displayName>Eagle Service Host</displayName> + <description>Set additional eagle service host, default: using current host</description> + </property> + <property> + <name>service.port</name> + <displayName>Eagle Service Port</displayName> + <description>Set additional eagle service port, default: using current port</description> + </property> </configuration> <streams> <stream> http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/config.json ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/config.json b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/config.json new file mode 100644 index 0000000..185e791 --- /dev/null +++ b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/config.json @@ -0,0 +1,68 @@ +{ + "master": { + "nonheap": "hadoop.memory.nonheapmemoryusage.used", + "heap": "hadoop.memory.heapmemoryusage.used", + "averageload": "hadoop.hbase.master.server.averageload", + "ritcount": "hadoop.hbase.master.assignmentmanger.ritcount", + "ritcountoverthreshold": "hadoop.hbase.master.assignmentmanger.ritcountoverthreshold", + "AssignNumOps": "hadoop.hbase.master.assignmentmanger.assign_num_ops", + "AssignMin": "hadoop.hbase.master.assignmentmanger.assign_min", + "AssignMax": "hadoop.hbase.master.assignmentmanger.assign_max", + "AssignPercentile75th": "hadoop.hbase.master.assignmentmanger.assign_75th_percentile", + "AssignPercentile95th": "hadoop.hbase.master.assignmentmanger.assign_95th_percentile", + "AssignPercentile99th": "hadoop.hbase.master.assignmentmanger.assign_99th_percentile", + "BulkAssignNum_ops": "hadoop.hbase.master.assignmentmanger.bulkassign_num_ops", + "BulkAssignMin": "hadoop.hbase.master.assignmentmanger.bulkassign_min", + "BulkAssignMax": "hadoop.hbase.master.assignmentmanger.bulkassign_max", + "BulkAssignPercentile75th": "hadoop.hbase.master.assignmentmanger.bulkassign_75th_percentile", + "BulkAssignPercentile95th": "hadoop.hbase.master.assignmentmanger.bulkassign_95th_percentile", + "BulkAssignPercentile99th": "hadoop.hbase.master.assignmentmanger.bulkassign_99th_percentile", + "BalancerClusterNum_ops": "hadoop.hbase.master.balancer.balancercluster_num_ops", + "BalancerClusterMin": "hadoop.hbase.master.balancer.balancercluster_min", + "BalancerClusterMax": "hadoop.hbase.master.balancer.balancercluster_max", + "BalancerClusterPercentile75th": "hadoop.hbase.master.balancer.balancercluster_75th_percentile", + "BalancerClusterPercentile95th": "hadoop.hbase.master.balancer.balancercluster_95th_percentile", + "BalancerClusterPercentile99th": "hadoop.hbase.master.balancer.balancercluster_99th_percentile", + "HlogSplitTimeMin": "hadoop.hbase.master.filesystem.hlogsplittime_min", + "HlogSplitTimeMax": "hadoop.hbase.master.filesystem.hlogsplittime_max", + "HlogSplitTimePercentile75th": "hadoop.hbase.master.filesystem.hlogsplittime_75th_percentile", + "HlogSplitTimePercentile95th": "hadoop.hbase.master.filesystem.hlogsplittime_95th_percentile", + "HlogSplitTimePercentile99th": "hadoop.hbase.master.filesystem.hlogsplittime_99th_percentile", + "HlogSplitSizeMin": "hadoop.hbase.master.filesystem.hlogsplitsize_min", + "HlogSplitSizeMax": "hadoop.hbase.master.filesystem.hlogsplitsize_max", + "MetaHlogSplitTimeMin": "hadoop.hbase.master.filesystem.metahlogsplittime_min", + "MetaHlogSplitTimeMax": "hadoop.hbase.master.filesystem.metahlogsplittime_max", + "MetaHlogSplitTimePercentile75th": "hadoop.hbase.master.filesystem.metahlogsplittime_75th_percentile", + "MetaHlogSplitTimePercentile95th": "hadoop.hbase.master.filesystem.metahlogsplittime_95th_percentile", + "MetaHlogSplitTimePercentile99th": "hadoop.hbase.master.filesystem.metahlogsplittime_99th_percentile", + "MetaHlogSplitSizeMin": "hadoop.hbase.master.filesystem.metahlogsplitsize_min", + "MetaHlogSplitSizeMax": "hadoop.hbase.master.filesystem.metahlogsplitsize_max" + }, + "regionserver": { + "nonheap" : "hadoop.memory.nonheapmemoryusage.used", + "heap" : "hadoop.memory.heapmemoryusage.used", + "directmemory" : "hadoop.bufferpool.direct.memoryused", + "GC count" : "hadoop.hbase.jvm.gccount", + "GC TimeMillis" : "hadoop.hbase.jvm.gctimemillis", + "QueueSize" : "hadoop.hbase.ipc.ipc.queuesize", + "NumCallsInGeneralQueue" : "hadoop.hbase.ipc.ipc.numcallsingeneralqueue", + "NumActiveHandler" : "hadoop.hbase.ipc.ipc.numactivehandler", + "IPC Queue Time (99th" : "hadoop.hbase.ipc.ipc.queuecalltime_99th_percentile", + "IPC Process Time (99th" : "hadoop.hbase.ipc.ipc.processcalltime_99th_percentile", + "QueueCallTime_num_ops" : "hadoop.hbase.ipc.ipc.queuecalltime_num_ops", + "ProcessCallTime_num_ops" : "hadoop.hbase.ipc.ipc.processcalltime_num_ops", + "RegionCount" : "hadoop.hbase.regionserver.server.regioncount", + "StoreCount" : "hadoop.hbase.regionserver.server.storecount", + "MemStoreSize" : "hadoop.hbase.regionserver.server.memstoresize", + "StoreFileSize" : "hadoop.hbase.regionserver.server.storefilesize", + "TotalRequestCount" : "hadoop.hbase.regionserver.server.totalrequestcount", + "ReadRequestCount" : "hadoop.hbase.regionserver.server.readrequestcount", + "WriteRequestCount" : "hadoop.hbase.regionserver.server.writerequestcount", + "SlitQueueLength" : "hadoop.hbase.regionserver.server.splitqueuelength", + "CompactionQueueLength" : "hadoop.hbase.regionserver.server.compactionqueuelength", + "FlushQueueLength" : "hadoop.hbase.regionserver.server.flushqueuelength", + "BlockCacheSize" : "hadoop.hbase.regionserver.server.blockcachesize", + "BlockCacheHitCount" : "hadoop.hbase.regionserver.server.blockcachehitcount", + "BlockCacheCountHitPercent" : "hadoop.hbase.regionserver.server.blockcounthitpercent" + } +} http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/overview.js ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/overview.js b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/overview.js index a02bed3..e10a0ce 100644 --- a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/overview.js +++ b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/overview.js @@ -21,52 +21,154 @@ * `register` without params will load the module which using require */ register(function (hadoopMetricApp) { - hadoopMetricApp.controller("overviewCtrl", function ($scope, PageConfig) { + hadoopMetricApp.controller("overviewCtrl", function ($q, $wrapState, $scope, PageConfig, METRIC, Time) { + var cache = {}; + $scope.site = $wrapState.param.siteId; + var activeMasterInfo = METRIC.hbaseActiveMaster($scope.site); + PageConfig.title = 'Overview'; + var storageOption = { + animation: false, + tooltip: { + formatter: function (points) { + return points[0].name + "<br/>" + + $.map(points, function (point) { + return '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + point.color + '"></span> ' + + point.seriesName + ": " + + common.number.abbr(point.value, true, 0); + }).reverse().join("<br/>"); + } + }, + yAxis: [{ + axisLabel: { + formatter: function (value) { + return common.number.abbr(value, true); + } + } + }] + }; + $scope.metricList = {}; - $scope.commonOption = {}; + function generateHbaseMetric(name, flag) { + var startTime = Time.startTime(); + var endTime = Time.endTime(); + var interval = Time.diffInterval(startTime, endTime); + var intervalMin = interval / 1000 / 60; + var trendStartTime = Time.align(startTime, interval); + var trendEndTime = Time.align(endTime, interval); - // Mock series data - function mockMetric(name, option, count) { - count = count || 1; - var now = +new Date(); + $scope.site = $wrapState.param.siteId; - var series = []; - for (var i = 0 ; i < count ; i += 1) { - var data = []; + return cache[name] = cache[name] || activeMasterInfo._promise.then(function (res) { + var hostname = cache[hostname] = cache[hostname] || res[0].tags.hostname; + $scope.defaultHostname = $wrapState.param.hostname || hostname; - for(var j = 0 ; j < 30 ; j += 1) { - data.push({x: now + j * 1000 * 60, y: Math.random() * 100}); - } + var jobCond = { + site: $scope.site, + component: "hbasemaster", + host: $scope.defaultHostname + }; + return METRIC.aggMetricsToEntities(METRIC.hbaseMetricsAggregation(jobCond, name, ["site"], "avg(value)", intervalMin, trendStartTime, trendEndTime), flag) + ._promise.then(function (list) { + var metricFlag = $.map(list, function (metrics) { + return metrics[0].flag; + }); + return [metricFlag, list]; + }); + }); + } - series.push($.extend({ - name: name + '_' + i, - type: 'line', - data: data, - showSymbol: false, - }, option)); - } + function mergeMetricToOneSeries(metricTitle, metrics, legendName, dataOption, option) { + var series = []; + $.each(metrics, function (i, metricMap) { + if(typeof metricMap !== 'undefined') { + series.push(METRIC.metricsToSeries(legendName[i], metricMap[0], option)); + } + }); return { - title: name, - series: series + title: metricTitle, + series: series, + option: dataOption || {} }; } - $scope.metricList = [ - mockMetric('name1', {}), - mockMetric('name2', {smooth:true}), - mockMetric('name3', {areaStyle: {normal: {}}}), - mockMetric('name4', {type: 'bar'}), - mockMetric('name1', {}, 2), - mockMetric('name2', {smooth:true}, 2), - mockMetric('name3', {areaStyle: {normal: {}}, stack: 'one'}, 2), - mockMetric('name4', {type: 'bar', stack: 'one'}, 2), - mockMetric('name1', {}, 3), - mockMetric('name2', {smooth:true}, 3), - mockMetric('name3', {areaStyle: {normal: {}}, stack: 'one'}, 3), - mockMetric('name4', {type: 'bar', stack: 'one'}, 3), - ]; + // TODO: Optimize the chart count + // TODO: ECharts dynamic refresh series bug: https://github.com/ecomfe/echarts/issues/4033 + + + $scope.refresh = function () { + var hbaseservers = METRIC.hbasehostStatus({site: $scope.site}); + var metricspromies = []; + METRIC.getMetricObj().then(function (res) { + var masterMetricList = res.master; + for (var metricKey in masterMetricList) { + metricspromies.push(generateHbaseMetric(masterMetricList[metricKey], metricKey)); + } + $q.all(metricspromies).then(function (resp) { + var metricObj = {}; + for(var i=0; i < resp.length; i+=1) { + metricObj[resp[i][0]] = resp[i][1]; + } + return metricObj; + }).then(function (seriesObj) { + $scope.metricList = [ + mergeMetricToOneSeries("MemoryUsage", [seriesObj["nonheap"], seriesObj["heap"]], ["nonheap", "heap"], storageOption, {areaStyle: {normal: {}}}), + mergeMetricToOneSeries("Master Averageload", [seriesObj["averageload"]], ["averageload"]), + mergeMetricToOneSeries("Ritcount", [seriesObj["ritcount"], seriesObj["ritcountoverthreshold"]], ["ritcount", "ritcountoverthreshold"]), + mergeMetricToOneSeries("Assign", [seriesObj["AssignNumOps"], seriesObj["AssignMin"], seriesObj["AssignMax"]], ["numOps", "Min", "Max"]), + mergeMetricToOneSeries("Assign Percentile", [seriesObj["AssignPercentile75th"], seriesObj["AssignPercentile95th"], seriesObj["AssignPercentile99th"]], ["75th", "95th", "99th"]), + mergeMetricToOneSeries("BulkAssign", [seriesObj["BulkAssignNum_ops"], seriesObj["BulkAssignMin"], seriesObj["BulkAssignMax"]], ["num_ops", "min", "max"]), + mergeMetricToOneSeries("BulkAssign Percentile", [seriesObj["BulkAssignPercentile75th"], seriesObj["BulkAssignPercentile95th"], seriesObj["BulkAssignPercentile99th"]], ["75th", "95th", "99th"]), + mergeMetricToOneSeries("BalancerCluster", [seriesObj["BalancerClusterNum_ops"], seriesObj["BalancerClusterMin"], seriesObj["BalancerClusterMax"]], ["num_ops", "min", "max"]), + mergeMetricToOneSeries("BalancerCluster Percentile", [seriesObj["BalancerClusterPercentile75th"], seriesObj["BalancerClusterPercentile95th"], seriesObj["BalancerClusterPercentile99th"]], ["75th", "95th", "99th"]), + mergeMetricToOneSeries("HlogSplitTime", [seriesObj["HlogSplitTimeMin"], seriesObj["HlogSplitTimeMax"]], ["HlogSplitTime_min", "HlogSplitTime_max"]), + mergeMetricToOneSeries("HlogSplitTime Percentile", [seriesObj["HlogSplitTimePercentile75th"], seriesObj["HlogSplitTimePercentile95th"], seriesObj["HlogSplitTimePercentile99th"]], ["75th", "95th", "99th"]), + mergeMetricToOneSeries("HlogSplitSize", [seriesObj["HlogSplitSizeMin"], seriesObj["HlogSplitSizeMax"]], ["Min", "Max"]), + mergeMetricToOneSeries("MetaHlogSplitTime", [seriesObj["MetaHlogSplitTimeMin"], seriesObj["MetaHlogSplitTimeMax"]], ["Min", "Max"]), + mergeMetricToOneSeries("MetaHlogSplitTime Percentile", [seriesObj["MetaHlogSplitTimePercentile75th"], seriesObj["MetaHlogSplitTimePercentile95th"], seriesObj["MetaHlogSplitTimePercentile99th"]], ["75th", "95th", "99th"]), + mergeMetricToOneSeries("MetaHlogSplitSize", [seriesObj["MetaHlogSplitSizeMin"], seriesObj["MetaHlogSplitSizeMax"]], ["Min", "Max"]) + ]; + }); + }); + + hbaseservers._promise.then(function (res) { + var regionhealtynum = 0; + var regiontotal = 0; + var hmasteractive; + var hmasterstandby; + $.each(res, function (i, server) { + var role = server.tags.role; + var status = server.status; + if (role === "regionserver") { + regiontotal++; + if (status === "live") { + regionhealtynum++; + } + } + else if (role === "hmaster") { + if (status === "active") { + hmasteractive = server; + } else { + hmasterstandby = server; + } + + } + }); + $scope.regionhealtynum = regionhealtynum; + $scope.regiontotal = regiontotal; + $scope.hmasteractive = hmasteractive; + $scope.hmasterstandby = hmasterstandby; + }) + }; + + + Time.onReload(function () { + cache = {}; + $scope.refresh(); + }, $scope); + $scope.refresh(); }); }); })(); +//# sourceURL=overview.js http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/regionDetailCtrl.js ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/regionDetailCtrl.js b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/regionDetailCtrl.js new file mode 100644 index 0000000..1f8c40d --- /dev/null +++ b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/regionDetailCtrl.js @@ -0,0 +1,164 @@ +/* + * 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. + */ + +(function () { + /** + * `register` without params will load the module which using require + */ + register(function (hadoopMetricApp) { + hadoopMetricApp.controller("regionDetailCtrl", function ($q, $wrapState, $scope, PageConfig, Time, METRIC) { + var cache = {}; + $scope.site = $wrapState.param.siteId; + $scope.hostname = $wrapState.param.hostname; + PageConfig.title = 'RegionServer ' + "(" + $scope.hostname + ")"; + $scope.metricList = []; + Time.autoRefresh = false; + + var sizeoption = { + animation: false, + tooltip: { + formatter: function (points) { + return points[0].name + "<br/>" + + $.map(points, function (point) { + return '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + point.color + '"></span> ' + + point.seriesName + ": " + + common.number.abbr(point.value, true); + }).reverse().join("<br/>"); + } + }, + legend: { + x: 'center', y: 'bottom' + }, + areaStyle: {normal: {}}, + yAxis: [{ + axisLabel: { + formatter: function (value) { + return common.number.abbr(value, true); + } + } + }] + }; + + var gctimeoption = { + legend: { + x: 'center', y: 'bottom' + }, + yAxis: [{ + axisLabel: { + formatter: function (value) { + return value / 1000 + ' S'; + } + } + }] + }; + + $scope.refresh = function () { + var startTime = Time.startTime(); + var endTime = Time.endTime(); + var metricspromies = []; + METRIC.getMetricObj().then(function (res) { + console.log(res.regionserver); + var masterMetricList = res.regionserver; + for (var metricKey in masterMetricList) { + metricspromies.push(generateHbaseMetric(masterMetricList[metricKey], startTime, endTime, metricKey)); + } + $q.all(metricspromies).then(function (resp) { + var metricObj = {}; + for(var i=0; i < resp.length; i+=1) { + metricObj[resp[i][0]] = resp[i][1]; + } + return metricObj; + }).then(function (seriesObj) { + $scope.metricList = []; + $scope.metricList.push(mergeSeries("Memory Usage", [seriesObj["nonheap"], seriesObj["heap"]], ["nonheap", "heap"], sizeoption)); + $scope.metricList.push(mergeSeries("Direct Memory Usage", [seriesObj["directmemory"]], ["directmemory"], sizeoption)); + $scope.metricList.push(mergeSeries("GC count", [seriesObj["GC count"]], ["GC count"], {})); + $scope.metricList.push(mergeSeries("GC TimeMillis", [seriesObj["GC TimeMillis"]], ["GC TimeMillis"], gctimeoption)); + $scope.metricList.push(mergeSeries("QueueSize", [seriesObj["QueueSize"]], ["QueueSize"], {})); + $scope.metricList.push(mergeSeries("NumCallsInGeneralQueue", [seriesObj["NumCallsInGeneralQueue"]], ["NumCallsInGeneralQueue"], {})); + $scope.metricList.push(mergeSeries("NumActiveHandler", [seriesObj["NumActiveHandler"]], ["NumActiveHandler"], {})); + $scope.metricList.push(mergeSeries("IPC Queue Time (99th)", [seriesObj["IPC Queue Time (99th)"]], ["IPC Queue Time (99th)"], {})); + $scope.metricList.push(mergeSeries("IPC Process Time (99th)", [seriesObj["IPC Process Time (99th)"]], ["IPC Process Time (99th)"], {})); + $scope.metricList.push(mergeSeries("QueueCallTime_num_ops", [seriesObj["QueueCallTime_num_ops"]], ["QueueCallTime_num_ops"], {})); + $scope.metricList.push(mergeSeries("ProcessCallTime_num_ops", [seriesObj["ProcessCallTime_num_ops"]], ["ProcessCallTime_num_ops"], {})); + $scope.metricList.push(mergeSeries("RegionCount", [seriesObj["RegionCount"]], ["RegionCount"], {})); + $scope.metricList.push(mergeSeries("StoreCount", [seriesObj["StoreCount"]], ["StoreCount"], {})); + $scope.metricList.push(mergeSeries("MemStoreSize", [seriesObj["MemStoreSize"]], ["MemStoreSize"], sizeoption)); + $scope.metricList.push(mergeSeries("StoreFileSize", [seriesObj["StoreFileSize"]], ["StoreFileSize"], sizeoption)); + $scope.metricList.push(mergeSeries("TotalRequestCount", [seriesObj["TotalRequestCount"]], ["TotalRequestCount"], {})); + $scope.metricList.push(mergeSeries("ReadRequestCount", [seriesObj["ReadRequestCount"]], ["ReadRequestCount"], {})); + $scope.metricList.push(mergeSeries("WriteRequestCount", [seriesObj["WriteRequestCount"]], ["WriteRequestCount"], {})); + $scope.metricList.push(mergeSeries("SlitQueueLength", [seriesObj["SlitQueueLength"]], ["SlitQueueLength"], {})); + $scope.metricList.push(mergeSeries("CompactionQueueLength", [seriesObj["CompactionQueueLength"]], ["CompactionQueueLength"], {})); + $scope.metricList.push(mergeSeries("FlushQueueLength", [seriesObj["FlushQueueLength"]], ["FlushQueueLength"], {})); + $scope.metricList.push(mergeSeries("BlockCacheSize", [seriesObj["BlockCacheSize"]], ["BlockCacheSize"], sizeoption)); + $scope.metricList.push(mergeSeries("BlockCacheHitCount", [seriesObj["BlockCacheHitCount"]], ["BlockCacheHitCount"], {})); + $scope.metricList.push(mergeSeries("BlockCacheCountHitPercent", [seriesObj["BlockCacheCountHitPercent"]], ["BlockCacheCountHitPercent"], {})); + }); + }); + + METRIC.regionserverStatus($scope.hostname, $scope.site)._promise.then(function (res) { + $scope.regionstatus = res; + }); + }; + Time.onReload(function () { + cache = {}; + $scope.refresh(); + }, $scope); + $scope.refresh(); + + + function generateHbaseMetric(name, startTime, endTime, flag) { + var interval = Time.diffInterval(startTime, endTime); + var intervalMin = interval / 1000 / 60; + var trendStartTime = Time.align(startTime, interval); + var trendEndTime = Time.align(endTime, interval); + + var condition = { + site: $scope.site, + component: "regionserver", + host: $scope.hostname + }; + return METRIC.aggMetricsToEntities(METRIC.hbaseMetricsAggregation(condition, name, ["site"], "avg(value)", intervalMin, trendStartTime, trendEndTime), flag) + ._promise.then(function (list) { + var metricFlag = $.map(list, function (metrics) { + return metrics[0].flag; + }); + return [metricFlag, list]; + }); + } + + function mergeSeries(title, metrics, linename, option) { + var series = []; + $.each(metrics, function (i, metricMap) { + $.map(metricMap, function (metric) { + if(typeof metric !== 'undefined') { + series.push(METRIC.metricsToSeries(linename[i], metric, option)); + } + }); + }); + return { + title: title, + series: series, + option: option || {} + }; + } + }); + }); +}) +(); http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/regionListCtrl.js ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/regionListCtrl.js b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/regionListCtrl.js new file mode 100644 index 0000000..bc7abd9 --- /dev/null +++ b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/ctrls/regionListCtrl.js @@ -0,0 +1,56 @@ +/* + * 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. + */ + +/* + * 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. + */ + +(function () { + /** + * `register` without params will load the module which using require + */ + register(function (hadoopMetricApp) { + + hadoopMetricApp.controller("regionListCtrl", function ($wrapState, $scope, PageConfig, METRIC) { + + // Initialization + PageConfig.title = "HBASE RegionServers"; + $scope.tableScope = {}; + $scope.live = METRIC.STATUS_LIVE; + $scope.dead = METRIC.STATUS_DEAD; + $scope.site = $wrapState.param.siteId; + $scope.searchPathList = [["tags", "hostname"], ["tags", "rack"], ["tags", "site"], ["status"]]; + $scope.regionserverList = METRIC.regionserverList($scope.site); + + }); + }); +})(); http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/index.js ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/index.js b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/index.js index 954cd6d..b81dfe4 100644 --- a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/index.js +++ b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/index.js @@ -23,24 +23,278 @@ var hadoopMetricApp = register(['ngRoute', 'ngAnimate', 'ui.router', 'eagle.service']); hadoopMetricApp.route("HadoopMetric", { - url: "/hadoopMetric/", + url: "/hadoopMetric?startTime&endTime", site: true, templateUrl: "partials/overview.html", controller: "overviewCtrl", + resolve: {time: true} }).route("HadoopMetric_HDFS", { url: "/hadoopMetric/hdfs", site: true, templateUrl: "partials/hdfs/index.html", controller: "hdfsCtrl", + resolve: {time: true} + }).route("regionDetail", { + url: "/hadoopMetric/regionDetail/:hostname", + site: true, + templateUrl: "partials/region/regionDetail.html", + controller: "regionDetailCtrl", + resolve: {time: true} + }).route("regionList", { + url: "/hadoopMetric/regionList", + site: true, + templateUrl: "partials/region/regionList.html", + controller: "regionListCtrl" + }).route("masterDetail", { + url: "/hadoopMetric/:hostname?startTime&endTime", + site: true, + reloadOnSearch: false, + templateUrl: "partials/overview.html", + controller: "overviewCtrl", + resolve: {time: true} }); - hadoopMetricApp.portal({name: "Services", icon: "heartbeat", list: [ - {name: "Overview", path: "hadoopMetric/"}, - {name: "HDFS", path: "hadoopMetric/hdfs"}, - ]}, true); + hadoopMetricApp.portal({ + name: "Services", icon: "heartbeat", list: [ + {name: "Overview", path: "hadoopMetric"}, + {name: "HDFS", path: "hadoopMetric/hdfs"} + ] + }, true); + + hadoopMetricApp.service("METRIC", function ($q, $http, Time, Site, Application) { + var METRIC = window._METRIC = {}; + METRIC.STATUS_LIVE = "live"; + METRIC.STATUS_DEAD = "dead"; + METRIC.QUERY_HBASE_METRICS = '${baseURL}/rest/entities?query=GenericMetricService[${condition}]{*}&metricName=${metric}&pageSize=${limit}'; + METRIC.QUERY_HBASE_METRICS_WITHTIME = '${baseURL}/rest/entities?query=GenericMetricService[${condition}]{*}&metricName=${metric}&pageSize=${limit}&startTime=${startTime}&endTime=${endTime}'; + METRIC.QUERY_HBASE_INSTANCE = '${baseURL}/rest/entities?query=HbaseServiceInstance[${condition}]{*}&pageSize=${limit}'; + METRIC.QUERY_HBASE_METRICS_INTERVAL = '${baseURL}/rest/entities?query=GenericMetricService[${condition}]<${groups}>{${field}}${order}${top}&metricName=${metric}&pageSize=${limit}&startTime=${startTime}&endTime=${endTime}&intervalmin=${intervalMin}&timeSeries=true'; + /** + * Fetch query content with current site application configuration + * @param {string} queryName + */ + var getQuery = METRIC.getQuery = function (queryName, siteId) { + var baseURL; + siteId = siteId || Site.current().siteId; + var app = Application.find("HADOOP_METRIC_MONITOR", siteId)[0]; + var host = app.configuration["service.host"]; + var port = app.configuration["service.port"]; + + if (!host && !port) { + baseURL = ""; + } else { + if (host === "localhost" || !host) { + host = location.hostname; + } + if (!port) { + port = location.port; + } + baseURL = "http://" + host + ":" + port; + } + + return common.template(METRIC["QUERY_" + queryName], {baseURL: baseURL}); + }; + + function wrapList(promise) { + var _list = []; + _list._done = false; + + _list._promise = promise.then( + /** + * @param {{}} res + * @param {{}} res.data + * @param {{}} res.data.obj + */ + function (res) { + _list.splice(0); + Array.prototype.push.apply(_list, res.data.obj); + _list._done = true; + return _list; + }); + return _list; + } + + function toFields(fields) { + return (fields || []).length > 0 ? $.map(fields, function (field) { + return "@" + field; + }).join(",") : "*"; + } + + METRIC.metricsToSeries = function (name, metrics, option, rawData) { + if (arguments.length === 4 && typeof rawData === "object") { + option = rawData; + rawData = false; + } + + var data = $.map(metrics, function (metric) { + return rawData ? metric.value[0] : { + x: metric.timestamp, + y: metric.value[0] + }; + }); + return $.extend({ + name: name, + showSymbol: false, + type: "line", + data: data + }, option || {}); + }; + + METRIC.get = function (url, params) { + return $http({ + url: url, + method: "GET", + params: params + }); + }; + + METRIC.condition = function (condition) { + return $.map(condition, function (value, key) { + return "@" + key + '="' + value + '"'; + }).join(" AND "); + }; + + + METRIC.hbaseMetrics = function (condition, metric, startTime, endTime, limit) { + var config = { + condition: METRIC.condition(condition), + startTime: Time.format(startTime), + endTime: Time.format(endTime), + metric: metric, + limit: limit || 10000 + }; + + var metrics_url = common.template(getQuery("HBASE_METRICS_WITHTIME"), config); + return wrapList(METRIC.get(metrics_url)); + }; + + METRIC.hbaseMetricsAggregation = function (condition, metric, groups, field, intervalMin, startTime, endTime, top, limit) { + var fields = field.split(/\s*,\s*/); + var orderId = -1; + var fieldStr = $.map(fields, function (field, index) { + var matches = field.match(/^([^\s]*)(\s+.*)?$/); + if (matches[2]) { + orderId = index; + } + return matches[1]; + }).join(", "); + + + var config = { + condition: METRIC.condition(condition), + startTime: Time.format(startTime), + endTime: Time.format(endTime), + metric: metric, + groups: toFields(groups), + field: fieldStr, + order: orderId === -1 ? "" : ".{" + fields[orderId] + "}", + top: top ? "&top=" + top : "", + intervalMin: intervalMin, + limit: limit || 10000 + }; + + var metrics_url = common.template(getQuery("HBASE_METRICS_INTERVAL"), config); + var _list = wrapList(METRIC.get(metrics_url)); + _list._aggInfo = { + groups: groups, + startTime: Time(startTime).valueOf(), + interval: intervalMin * 60 * 1000 + }; + _list._promise.then(function () { + _list.reverse(); + }); + return _list; + }; + + METRIC.aggMetricsToEntities = function (list, param, flatten) { + var _list = []; + _list.done = false; + _list._promise = list._promise.then(function () { + var _startTime = list._aggInfo.startTime; + var _interval = list._aggInfo.interval; + + $.each(list, function (i, obj) { + var tags = {}; + $.each(list._aggInfo.groups, function (j, group) { + tags[group] = obj.key[j]; + }); + + var _subList = $.map(obj.value[0], function (value, index) { + return { + timestamp: _startTime + index * _interval, + value: [value], + tags: tags, + flag: param + }; + }); + + if (flatten) { + _list.push.apply(_list, _subList); + } else { + _list.push(_subList); + } + }); + _list.done = true; + return _list; + }); + return _list; + }; + + + METRIC.hbasehostStatus = function (condition, limit) { + var config = { + condition: METRIC.condition(condition), + limit: limit || 10000 + }; + + var metrics_url = common.template(getQuery("HBASE_INSTANCE"), config); + return wrapList(METRIC.get(metrics_url)); + }; + + METRIC.hbaseActiveMaster = function (siteId) { + var condition = { + site: siteId, + role: "hmaster", + status: "active" + }; + return METRIC.hbasehostStatus(condition, 1); + }; + + METRIC.regionserverStatus = function (hostname, siteid) { + var hoststateinfo; + var condition = { + site: siteid, + role: "regionserver", + hostname: hostname + }; + hoststateinfo = METRIC.hbasehostStatus(condition, 1); + return hoststateinfo; + }; + + METRIC.regionserverList = function (siteid) { + var hoststateinfos; + var condition = { + site: siteid, + role: "regionserver" + }; + hoststateinfos = METRIC.hbasehostStatus(condition); + return hoststateinfos; + }; + + METRIC.getMetricObj = function () { + var deferred = $q.defer(); + $http.get("apps/hadoop_metric/config.json").success(function (resp) { + deferred.resolve(resp); + }); + return deferred.promise; + }; + return METRIC; + }); hadoopMetricApp.requireCSS("style/index.css"); hadoopMetricApp.require("widgets/availabilityChart.js"); hadoopMetricApp.require("ctrls/overview.js"); hadoopMetricApp.require("ctrls/hdfs.js"); + hadoopMetricApp.require("ctrls/regionDetailCtrl.js"); + hadoopMetricApp.require("ctrls/regionListCtrl.js"); })(); http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/overview.html ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/overview.html b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/overview.html index cb4d01c..13caebf 100644 --- a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/overview.html +++ b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/overview.html @@ -20,11 +20,37 @@ <div class="box-header with-border"> <span class="fa fa-television"></span> <h3 class="box-title"> - Summary + Service Summary Information </h3> </div> <div class="box-body"> - TODO: Your summary + + <table class="table table-striped"> + <tbody> + <tr ng-if="regiontotal > 0"> + <th>RegionServer Status</th> + <td class="text-break"> + <a ui-sref="regionList({siteId: site})" target="_blank">{{regiontotal}} RegionServers</a> + <span class="label label-success">{{regionhealtynum}} Healthy</span> + <span class="label label-danger">{{regiontotal - regionhealtynum}} UnHealthy</span> + </td> + </tr> + <tr ng-if="hmasteractive"> + <th>Active Hmaster Status</th> + <td class="text-break"> + <span ng-if="defaultHostname !== hmasteractive.tags.hostname" class="label label-success">(<a class="hadoopMetric-summary-a" ui-sref="masterDetail({siteId: site, hostname: hmasteractive.tags.hostname})">{{hmasteractive.tags.hostname}}</a>) Healthy</span> + <span ng-if="defaultHostname === hmasteractive.tags.hostname" class="label label-success">({{hmasteractive.tags.hostname}}) Healthy</span> + </td> + </tr> + <tr ng-if="hmasterstandby"> + <th>Standby Hmaster Status</th> + <td class="text-break"> + <span ng-if="defaultHostname !== hmasterstandby.tags.hostname" class="label label-success">(<a class="hadoopMetric-summary-a" ui-sref="masterDetail({siteId: site, hostname: hmasterstandby.tags.hostname})">{{hmasterstandby.tags.hostname}}</a>) Healthy</span> + <span ng-if="defaultHostname === hmasterstandby.tags.hostname" class="label label-success">({{hmasterstandby.tags.hostname}}) Healthy</span> + </td> + </tr> + </tbody> + </table> </div> </div> @@ -33,6 +59,7 @@ <span class="fa fa-line-chart"></span> <h3 class="box-title"> Metrics + <span>({{defaultHostname}})</span> </h3> </div> <div class="box-body no-padding"> @@ -40,10 +67,11 @@ <div class="col-sm-6 col-md-4 col-lg-3" ng-repeat="metric in metricList track by $index"> <div class="hadoopMetric-chart"> <h3>{{metric.title}}</h3> - <div chart class="hadoopMetric-chart-container" series="metric.series" option="commonOption"></div> - </div> + <div chart class="hadoopMetric-chart-container" series="metric.series" + option="metric.option"></div> </div> </div> </div> </div> </div> +</div> http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/region/regionDetail.html ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/region/regionDetail.html b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/region/regionDetail.html new file mode 100644 index 0000000..e95bd24 --- /dev/null +++ b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/region/regionDetail.html @@ -0,0 +1,105 @@ +<!-- + 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. + --> + +<div class="box box-primary"> + <div class="box-header with-border"> + <span class="fa fa-television"></span> + <h3 class="box-title"> + Summary + </h3> + </div> + <div class="box-body"> + <table class="table table-striped"> + <tbody ng-if="(regionstatus || []).length !== 0"> + <tr> + <th>Status</th> + <td class="text-break"> + <span ng-if="regionstatus[0].status==='live'" class="label label-success">Healthy</span> + <span ng-if="regionstatus[0].status!=='live'" class="label label-danger">UnHealthy</span> + </td> + </tr> + <tr> + <th>Rack</th> + <td class="text-break">{{regionstatus[0].tags.rack}}</td> + </tr> + <tr> + <th>MaxHeap</th> + <td class="text-break">{{regionstatus[0].maxHeapMB}} MB</td> + </tr> + <tr> + <th>UsedHeap</th> + <td class="text-break">{{regionstatus[0].usedHeapMB}} MB</td> + </tr> + <tr> + <th>NumRegions</th> + <td class="text-break">{{regionstatus[0].numRegions}}</td> + </tr> + <tr> + <th>NumRequests</th> + <td class="text-break">{{regionstatus[0].numRequests}}</td> + </tr> + </tbody> + <tbody ng-if="regionstatus.length === 0"> + <tr> + <th>Status</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + <tr> + <th>Rack</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + <tr> + <th>MaxHeap</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + <tr> + <th>UsedHeap</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + <tr> + <th>NumRegions</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + <tr> + <th>NumRequests</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + </tbody> + </table> + </div> +</div> + +<div class="box box-primary"> + <div class="box-header with-border"> + <span class="fa fa-line-chart"></span> + <h3 class="box-title"> + Metrics + </h3> + </div> + <div class="box-body no-padding"> + <div class="row border-split"> + <div class="col-sm-6 hadoopMetric-col-md-6 col-lg-3" ng-repeat="metric in metricList track by $index"> + <div class="hadoopMetric-chart"> + <h3>{{metric.title}}</h3> + <div chart class="hadoopMetric-chart-container" series="metric.series" option="metric.option"></div> + </div> + </div> + </div> + </div> +</div> +</div> http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/region/regionList.html ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/region/regionList.html b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/region/regionList.html new file mode 100644 index 0000000..507de72 --- /dev/null +++ b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/partials/region/regionList.html @@ -0,0 +1,53 @@ +<!-- + 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. + --> +<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})" 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> http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/style/index.css ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/style/index.css b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/style/index.css index 947120b..6ae1ea1 100644 --- a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/style/index.css +++ b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/style/index.css @@ -46,7 +46,7 @@ .hadoopMetric-widget { width: 100%; - box-shadow: 0 1px 1px rgba(0,0,0,0.1); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); border-radius: 2px; padding: 10px; } @@ -59,3 +59,8 @@ .hadoopMetric-widget .hadoopMetric-chart-container { height: 100px; } + +.hadoopMetric-summary-a { + color: #fff; +} + http://git-wip-us.apache.org/repos/asf/eagle/blob/257a3517/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/widgets/availabilityChart.js ---------------------------------------------------------------------- diff --git a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/widgets/availabilityChart.js b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/widgets/availabilityChart.js index fddcb88..75e6835 100644 --- a/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/widgets/availabilityChart.js +++ b/eagle-hadoop-metric/src/main/webapp/app/apps/hadoop_metric/widgets/availabilityChart.js @@ -97,7 +97,7 @@ $element.append( $("<div hadoop-metric-widget data-type='" + serviceType + "'>") ); - } + }; } hadoopMetricApp.widget("availabilityHDFSChart", withType('HDFS'), true);
