You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@eagle.apache.org by ji...@apache.org on 2017/02/07 09:36:03 UTC
eagle git commit: [EAGLE-884] JPM support queue trend view
Repository: eagle
Updated Branches:
refs/heads/master 5e4c937e3 -> ce53540f3
[EAGLE-884] JPM support queue trend view
* Add trend chart
* support queue drill down
* Capacity base line
Author: zombieJ <sm...@gmail.com>
Closes #794 from zombieJ/EAGLE-884.
Project: http://git-wip-us.apache.org/repos/asf/eagle/repo
Commit: http://git-wip-us.apache.org/repos/asf/eagle/commit/ce53540f
Tree: http://git-wip-us.apache.org/repos/asf/eagle/tree/ce53540f
Diff: http://git-wip-us.apache.org/repos/asf/eagle/diff/ce53540f
Branch: refs/heads/master
Commit: ce53540f3d3128ed9aeec2112d184fa214edca45
Parents: 5e4c937
Author: zombieJ <sm...@gmail.com>
Authored: Tue Feb 7 17:35:43 2017 +0800
Committer: zombieJ <sm...@gmail.com>
Committed: Tue Feb 7 17:35:43 2017 +0800
----------------------------------------------------------------------
.../main/webapp/app/apps/jpm/ctrl/queueCtrl.js | 230 +++++++++++++++++++
.../src/main/webapp/app/apps/jpm/index.js | 46 ++--
.../app/apps/jpm/partials/queue/overview.html | 57 +++++
.../main/webapp/app/apps/jpm/style/index.css | 8 +
eagle-server/src/main/webapp/app/dev/index.html | 6 +-
.../src/main/webapp/app/dev/public/css/main.css | 9 +
.../app/dev/public/js/services/pageSrv.js | 41 +++-
eagle-server/src/main/webapp/app/package.json | 2 +-
8 files changed, 378 insertions(+), 21 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/eagle/blob/ce53540f/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/ctrl/queueCtrl.js
----------------------------------------------------------------------
diff --git a/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/ctrl/queueCtrl.js b/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/ctrl/queueCtrl.js
new file mode 100644
index 0000000..70988f4
--- /dev/null
+++ b/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/ctrl/queueCtrl.js
@@ -0,0 +1,230 @@
+/*
+ * 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 (jpmApp) {
+ var QUEUE_ROOT = 'unassigned';
+
+ jpmApp.controller("queueCtrl", function ($q, $wrapState, $element, $scope, $timeout, PageConfig, Time, Entity, JPM) {
+ var TEXT_MAX_CAPACITY = 'Max Capacity';
+ var DISPLAY_MARK_NAME = ['Guaranteed Capacity', TEXT_MAX_CAPACITY];
+
+ $scope.site = $wrapState.param.siteId;
+ $scope.currentQueue = $wrapState.param.queue;
+ $scope.selectedQueue = '';
+ $scope.selectedSubQueue = '';
+ $scope.trendLoading = true;
+
+ PageConfig.title = "Queue";
+ PageConfig.subTitle = $scope.currentQueue || "Overview";
+ var navPath = PageConfig.navPath = [];
+
+ $scope.chartOption = {
+ 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 + ": " +
+ Math.floor(point.value) + '%';
+ }).reverse().join("<br/>");
+ }
+ },
+ yAxis: [{
+ axisLabel: {formatter: function (value) {
+ return value + '%';
+ }}
+ }]
+ };
+
+ // Load queue tree
+ (function () {
+ var startTime = new Time('startTime');
+ var endTime = startTime.clone().add(1, 'h');
+ JPM
+ .groups('RunningQueueService', { site: $scope.site, queue: $scope.currentQueue }, ['queue', 'parentQueue'], 'count', 60, startTime, endTime)
+ ._promise
+ .then(function (list) {
+ $.each(list, function (i, entity) {
+ var parent = entity.key[1];
+ $scope.parentQueue = parent === QUEUE_ROOT ? null : parent;
+
+ // Update navigation path
+ navPath.push(
+ {
+ title: $scope.parentQueue || 'queue list',
+ icon: 'sitemap',
+ param: ['siteId', 'startTime', 'endTime', $scope.parentQueue && 'queue=' + $scope.parentQueue],
+ path: "/jpm/queue"
+ },
+ {title: $scope.currentQueue}
+ );
+
+ return false;
+ });
+ });
+ })();
+
+ // Refresh Trend Chart
+ $scope.refresh = function () {
+ $scope.trendLoading = true;
+ var startTime = new Time('startTime');
+ var endTime = new Time('endTime');
+ var intervalMin = Time.diffInterval(startTime, endTime) / 1000 / 60;
+ var condition = {site: $scope.site};
+ if ($scope.currentQueue) condition.parentQueue = $scope.currentQueue;
+
+ var promiseList = [];
+ // Load sub queue trend
+ promiseList.push(JPM.aggMetricsToEntities(
+ JPM.groups('RunningQueueService', condition, ['queue', 'parentQueue'], 'max(absoluteUsedCapacity)', intervalMin, startTime, endTime)
+ )._promise.then(function (list) {
+ $scope.subQueueList = [];
+
+ // Filter top queue
+ var queueTrendSeries = $.map(list, function (subList) {
+ var tags = subList[0].tags;
+ if (!$scope.currentQueue && tags.parentQueue !== QUEUE_ROOT) return;
+
+ var name = subList[0].tags.queue;
+ $scope.subQueueList.push(name);
+ return JPM.metricsToSeries(name, subList, {
+ stack: "queue",
+ areaStyle: {normal: {}}
+ });
+ });
+
+ $scope.selectedQueue = common.getValueByPath(queueTrendSeries, ['0', 'name']);
+ $scope.refreshQueueStatistic();
+
+ return queueTrendSeries;
+ }));
+
+ if ($scope.currentQueue) {
+ // Load current queue trend
+ promiseList.push(JPM.aggMetricsToEntities(
+ JPM.groups('RunningQueueService',
+ { site: $scope.site, queue: $scope.currentQueue },
+ ['queue'],
+ 'max(absoluteUsedCapacity), max(memory), max(absoluteCapacity), max(absoluteMaxCapacity)',
+ intervalMin, startTime, endTime)
+ )._promise.then(function (list) {
+ // Filter top queue
+ return $.map(list, function (valueSeries, seriesIndex) {
+ var seriesName = valueSeries[0].tags.queue;
+ var option = {};
+ if (seriesIndex === 0) {
+ option.areaStyle = {normal: {}};
+ } else if (seriesIndex === 1) {
+ return;
+ } else {
+ seriesName = DISPLAY_MARK_NAME[seriesIndex - 2];
+ var markDisplayText = seriesName;
+
+ if (seriesName === TEXT_MAX_CAPACITY) {
+ var lastMemory = list[1][list[1].length - 1].value[0];
+ var lastCapacity = list[0][list[0].length - 1].value[0];
+ var lastMaxCapacity = list[seriesIndex][list[seriesIndex].length - 1].value[0];
+ var lastMaxMemory = lastMemory / lastCapacity * lastMaxCapacity;
+ lastMaxMemory *= 1024 * 1024;
+
+ if (!isNaN(lastMaxMemory)) markDisplayText += '(Memory:' + common.number.abbr(lastMaxMemory, true, 0) + ')';
+ }
+
+ var pointValue = common.getValueByPath(valueSeries, [valueSeries.length - 1, 'value', 0], 0);
+ option = {
+ markPoint: {
+ silent: true,
+ label: {
+ normal: {
+ formatter: function () {
+ return markDisplayText;
+ },
+ position: 'insideRight',
+ textStyle: {
+ color: '#333',
+ fontSize: 12,
+ }
+ }
+ },
+ data: [
+ {
+ name: '',
+ coord: [valueSeries.length - 1, pointValue],
+ symbolSize: 30,
+ itemStyle: {
+ normal: {color: 'rgba(0,0,0,0)'}
+ }
+ }
+ ],
+ },
+ lineStyle: {
+ normal: { type: 'dotted' }
+ }
+ };
+ }
+
+ return JPM.metricsToSeries(seriesName, valueSeries, option);
+ });
+ }));
+ }
+
+ $q.all(promiseList).then(function (seriesList) {
+
+ var subQueuesSeries = seriesList[0];
+ $scope.queueTrendSeries = subQueuesSeries;
+
+ if (seriesList[1]) {
+ var queueSeries = [seriesList[1][0]];
+ var capacitySeries = seriesList[1].slice(1);
+
+ if (!subQueuesSeries.length) {
+ $scope.queueTrendSeries = queueSeries;
+ }
+ $scope.queueTrendSeries = $scope.queueTrendSeries.concat(capacitySeries);
+ }
+ $scope.trendLoading = false;
+ });
+ };
+
+ // Refresh Queue static info
+ $scope.refreshQueueStatistic = function () {
+ var startTime = new Time('startTime');
+ var endTime = new Time('endTime');
+ };
+
+ // Go to sub queue view
+ $scope.switchToSubQueue = function () {
+ $wrapState.go(".", {
+ queue: $scope.selectedSubQueue,
+ startTime: Time.format('startTime'),
+ endTime: Time.format('endTime'),
+ });
+ };
+
+ Time.onReload(function () {
+ $scope.refresh();
+ }, $scope);
+ $scope.refresh();
+
+ });
+ });
+})();
http://git-wip-us.apache.org/repos/asf/eagle/blob/ce53540f/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/index.js
----------------------------------------------------------------------
diff --git a/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/index.js b/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/index.js
index 7348853..234c539 100644
--- a/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/index.js
+++ b/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/index.js
@@ -55,18 +55,25 @@
reloadOnSearch: false,
templateUrl: "partials/job/compare.html",
controller: "compareCtrl"
+
+ }).route("jpmQueue", {
+ url: "/jpm/queue?queue&startTime&endTime",
+ site: true,
+ templateUrl: "partials/queue/overview.html",
+ controller: "queueCtrl",
+ resolve: { time: true }
});
jpmApp.portal({name: "YARN Jobs", icon: "taxi", list: [
{name: "Overview", path: "jpm/overview"},
{name: "Job Statistics", path: "jpm/statistics"},
- {name: "Job List", path: "jpm/list"}
+ {name: "Job List", path: "jpm/list"},
+ {name: "Queue", path: "jpm/queue"}
]}, true);
jpmApp.service("JPM", function ($q, $http, Time, Site, Application) {
var JPM = window._JPM = {};
- // TODO: timestamp support
JPM.QUERY_LIST = '${baseURL}/rest/entities?query=${query}[${condition}]{${fields}}&pageSize=${limit}&startTime=${startTime}&endTime=${endTime}';
JPM.QUERY_GROUPS = '${baseURL}/rest/entities?query=${query}[${condition}]<${groups}>{${field}}${order}${top}&pageSize=${limit}&startTime=${startTime}&endTime=${endTime}';
JPM.QUERY_GROUPS_INTERVAL = '${baseURL}/rest/entities?query=${query}[${condition}]<${groups}>{${field}}${order}${top}&pageSize=${limit}&startTime=${startTime}&endTime=${endTime}&intervalmin=${intervalMin}&timeSeries=true';
@@ -142,6 +149,7 @@
};
JPM.condition = function (condition) {
+ if (typeof condition === 'string') return condition;
return $.map(condition, function (value, key) {
return "@" + key + '="' + value + '"';
}).join(" AND ");
@@ -189,7 +197,8 @@
_list._aggInfo = {
groups: groups,
startTime: Time(startTime).valueOf(),
- interval: intervalMin * 60 * 1000
+ interval: intervalMin * 60 * 1000,
+ order: fields[orderId]
};
_list._promise.then(function () {
if(top) _list.reverse();
@@ -310,7 +319,7 @@
_list._aggInfo = {
groups: groups,
startTime: Time(startTime).valueOf(),
- interval: intervalMin * 60 * 1000
+ interval: intervalMin * 60 * 1000,
};
_list._promise.then(function () {
_list.reverse();
@@ -331,19 +340,23 @@
tags[group] = obj.key[j];
});
- var _subList = $.map(obj.value[0], function (value, index) {
- return {
- timestamp: _startTime + index * _interval,
- value: [value],
- tags: tags
- };
- });
+ $.each(obj.value, function (j, values) {
+ if (list._aggInfo.order && j === list.length - 1) return;
- if(flatten) {
- _list.push.apply(_list, _subList);
- } else {
- _list.push(_subList);
- }
+ var _subList = $.map(values, function (value, index) {
+ return {
+ timestamp: _startTime + index * _interval,
+ value: [value],
+ tags: tags
+ };
+ });
+
+ if(flatten) {
+ _list.push.apply(_list, _subList);
+ } else {
+ _list.push(_subList);
+ }
+ });
});
_list.done = true;
return _list;
@@ -484,4 +497,5 @@
jpmApp.require("ctrl/detailCtrl.js");
jpmApp.require("ctrl/jobTaskCtrl.js");
jpmApp.require("ctrl/compareCtrl.js");
+ jpmApp.require("ctrl/queueCtrl.js");
})();
http://git-wip-us.apache.org/repos/asf/eagle/blob/ce53540f/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/partials/queue/overview.html
----------------------------------------------------------------------
diff --git a/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/partials/queue/overview.html b/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/partials/queue/overview.html
new file mode 100644
index 0000000..732fbb2
--- /dev/null
+++ b/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/partials/queue/overview.html
@@ -0,0 +1,57 @@
+<!--
+ 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">
+ Queue Capacity Trend
+ </h3>
+ <div class="box-tools" ng-show="subQueueList.length">
+ <select class="form-control input-sm" ng-model="selectedSubQueue" ng-change="switchToSubQueue()">
+ <option value="">[View Sub Queue]</option>
+ <option ng-repeat="queue in subQueueList track by $index" value="{{queue}}">{{queue}}</option>
+ </select>
+ </div>
+ </div>
+ <div class="box-body">
+ <div class="jpm-chart">
+ <div chart class="jpm-chart-container" series="queueTrendSeries" option="chartOption"></div>
+ <h1 class="jpm-chart-tip" ng-if="queueTrendSeries && queueTrendSeries.length === 0">No Data</h1>
+ </div>
+ </div>
+
+ <div ng-if="trendLoading" class="overlay">
+ <i class="fa fa-refresh fa-spin"></i>
+ </div>
+</div>
+
+<!-- div class="nav-tabs-custom">
+ <ul class="nav nav-tabs">
+ <li class="active"><a data-toggle="tab" href="#queueUser">User</a></li>
+ <li><a data-toggle="tab" href="#queueJob">Job</a></li>
+
+ <li class="pull-right">
+ <select class="form-control" ng-model="selectedQueue" ng-change="refreshQueueStatistic()">
+ <option ng-repeat="queue in subQueueList track by $index" value="{{queue}}">{{queue}}</option>
+ </select>
+ </li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane active"></div>
+ </div>
+</div -->
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/eagle/blob/ce53540f/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/style/index.css
----------------------------------------------------------------------
diff --git a/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/style/index.css b/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/style/index.css
index fbe238f..f63d67c 100644
--- a/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/style/index.css
+++ b/eagle-jpm/eagle-jpm-web/src/main/webapp/app/apps/jpm/style/index.css
@@ -39,6 +39,14 @@
height: 350px;
}
+.jpm-chart .jpm-chart-tip {
+ position: absolute;
+ top: 50%;
+ margin: -20px 0 0 0;
+ width: 100%;
+ text-align: center;
+}
+
.with-border .jpm-chart {
padding-bottom: 15px;
margin-bottom: 15px;
http://git-wip-us.apache.org/repos/asf/eagle/blob/ce53540f/eagle-server/src/main/webapp/app/dev/index.html
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/index.html b/eagle-server/src/main/webapp/app/dev/index.html
index 74d5c57..26b12ee 100644
--- a/eagle-server/src/main/webapp/app/dev/index.html
+++ b/eagle-server/src/main/webapp/app/dev/index.html
@@ -162,13 +162,13 @@
<ol class="breadcrumb">
- <li ng-repeat="navPath in PageConfig.navPath">
+ <li ng-repeat="navPath in PageConfig.getNavPath() track by $index">
<span ng-if="!navPath.path">
- <span class="fa fa-home" ng-if="$first"></span>
+ <span class="fa fa-{{navPath.icon || 'home'}}" ng-if="$first"></span>
{{navPath.title || navPath.path}}
</span>
<a ng-if="navPath.path" ng-href="#{{navPath.path}}">
- <span class="fa fa-home" ng-if="$first"></span>
+ <span class="fa fa-{{navPath.icon || 'home'}}" ng-if="$first"></span>
{{navPath.title || navPath.path}}
</a>
</li>
http://git-wip-us.apache.org/repos/asf/eagle/blob/ce53540f/eagle-server/src/main/webapp/app/dev/public/css/main.css
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/css/main.css b/eagle-server/src/main/webapp/app/dev/public/css/main.css
index 895d514..8583513 100644
--- a/eagle-server/src/main/webapp/app/dev/public/css/main.css
+++ b/eagle-server/src/main/webapp/app/dev/public/css/main.css
@@ -277,6 +277,15 @@ ul.stepGuide li > .title {
overflow-x: auto;
}
+.box-header > .box-tools {
+ white-space: nowrap;
+}
+
+.box-header > .box-tools > .form-control {
+ display: inline-block;
+ width: initial;
+}
+
/* ========================================================================
* = Tab =
* ======================================================================== */
http://git-wip-us.apache.org/repos/asf/eagle/blob/ce53540f/eagle-server/src/main/webapp/app/dev/public/js/services/pageSrv.js
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/dev/public/js/services/pageSrv.js b/eagle-server/src/main/webapp/app/dev/public/js/services/pageSrv.js
index 2c61087..f4ea2f4 100644
--- a/eagle-server/src/main/webapp/app/dev/public/js/services/pageSrv.js
+++ b/eagle-server/src/main/webapp/app/dev/public/js/services/pageSrv.js
@@ -24,7 +24,7 @@
// ============================================================
// = Page =
// ============================================================
- serviceModule.service('PageConfig', function() {
+ serviceModule.service('PageConfig', function($wrapState) {
function PageConfig() {
}
@@ -35,6 +35,45 @@
PageConfig.hideTitle = false;
};
+ var cachedNavPath = [];
+ var cachedGenNavPath = [];
+ PageConfig.getNavPath = function () {
+ if (cachedNavPath !== PageConfig.navPath || cachedGenNavPath.length !== cachedNavPath.length) {
+ cachedNavPath = PageConfig.navPath;
+ cachedGenNavPath = $.map(cachedNavPath, function (navPath) {
+ var pathEntity = $.extend({}, navPath);
+
+ if (!pathEntity.path || !pathEntity.param) return pathEntity;
+
+ // Parse param as `key=value` format
+ var params = {};
+ $.each(pathEntity.param, function (i, param) {
+ if (!param) return;
+
+ var match = param.match(/^([^=]+)(=(.*))?$/);
+ var key = match[1];
+ var value = match[3];
+ params[key] = value !== undefined ? value : $wrapState.param[key];
+ });
+
+ // Generate path with param
+ var path = "/" + pathEntity.path.replace(/^[\\\/]/, "");
+ if (params.siteId) {
+ pathEntity.path = "/site/" + $wrapState.param.siteId + path;
+ delete params.siteId;
+ } else {
+ pathEntity.path = path;
+ }
+ pathEntity.path += '?' + $.map(params, function (value, key) {
+ return key + '=' + value;
+ }).join('&');
+
+ return pathEntity;
+ });
+ }
+ return cachedGenNavPath;
+ };
+
return PageConfig;
});
http://git-wip-us.apache.org/repos/asf/eagle/blob/ce53540f/eagle-server/src/main/webapp/app/package.json
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/webapp/app/package.json b/eagle-server/src/main/webapp/app/package.json
index 4ee3eda..2c5d272 100644
--- a/eagle-server/src/main/webapp/app/package.json
+++ b/eagle-server/src/main/webapp/app/package.json
@@ -23,7 +23,7 @@
"angular-ui-router": "0.3.1",
"bootstrap": "3.3.6",
"d3": "3.5.16",
- "echarts": "^3.3.2",
+ "echarts": "^3.4.0",
"font-awesome": "4.7.0",
"jquery": "2.2.4",
"jquery-slimscroll": "1.3.6",