123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- /**
- * 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.
- */
- var App = require('app');
- App.GraphWidgetView = Em.View.extend(App.WidgetMixin, {
- templateName: require('templates/common/widget/graph_widget'),
- /**
- * common metrics container
- * @type {Array}
- */
- metrics: [],
- /**
- * 3600 sec in 1 hour
- * @const
- */
- TIME_FACTOR: 3600,
- /**
- * custom time range, set when graph opened in popup
- * @type {number|null}
- */
- customTimeRange: null,
- /**
- * value in seconds
- * @type {number}
- */
- timeRange: function () {
- var timeRange = parseInt(this.get('content.properties.time_range'));
- if (isNaN(timeRange)) {
- //1h - default time range
- timeRange = 1;
- }
- return this.get('customTimeRange') || timeRange * this.get('TIME_FACTOR');
- }.property('content.properties.time_range', 'customTimeRange'),
- /**
- * value in ms
- * @type {number}
- */
- timeStep: 15,
- /**
- * @type {Array}
- */
- data: [],
- drawWidget: function () {
- if (this.get('isLoaded')) {
- this.set('data', this.calculateValues());
- }
- },
- /**
- * calculate series datasets for graph widgets
- */
- calculateValues: function () {
- var metrics = this.get('metrics');
- var seriesData = [];
- if (this.get('content.values')) {
- this.get('content.values').forEach(function (value) {
- var expression = this.extractExpressions(value)[0];
- var computedData;
- var datasetKey;
- if (expression) {
- datasetKey = value.value.match(this.get('EXPRESSION_REGEX'))[0];
- computedData = this.computeExpression(expression, metrics)[datasetKey];
- //exclude empty datasets
- if (computedData.length > 0) {
- seriesData.push({
- name: value.name,
- data: computedData
- });
- }
- }
- }, this);
- }
- return seriesData;
- },
- /**
- * compute expression
- *
- * @param {string} expression
- * @param {object} metrics
- * @returns {object}
- */
- computeExpression: function (expression, metrics) {
- var validExpression = true,
- value = [],
- dataLinks = {},
- dataLength = -1,
- beforeCompute,
- result = {},
- isDataCorrupted = false,
- isPointNull = false;
- //replace values with metrics data
- expression.match(this.get('VALUE_NAME_REGEX')).forEach(function (match) {
- if (isNaN(match)) {
- if (metrics.someProperty('name', match)) {
- dataLinks[match] = metrics.findProperty('name', match).data;
- if (!isDataCorrupted) {
- isDataCorrupted = (dataLength !== -1 && dataLength !== dataLinks[match].length);
- }
- dataLength = (dataLinks[match].length > dataLength) ? dataLinks[match].length : dataLength;
- } else {
- validExpression = false;
- console.warn('Metrics with name "' + match + '" not found to compute expression');
- }
- }
- });
- if (validExpression) {
- if (isDataCorrupted) {
- this.adjustData(dataLinks, dataLength);
- }
- for (var i = 0, timestamp; i < dataLength; i++) {
- isPointNull = false;
- beforeCompute = expression.replace(this.get('VALUE_NAME_REGEX'), function (match) {
- if (isNaN(match)) {
- timestamp = dataLinks[match][i][1];
- isPointNull = (isPointNull) ? true : (Em.isNone(dataLinks[match][i][0]));
- return dataLinks[match][i][0];
- } else {
- return match;
- }
- });
- var dataLinkPointValue = isPointNull ? null : Number(window.eval(beforeCompute));
- // expression resulting into `0/0` will produce NaN Object which is not a valid series data value for RickShaw graphs
- if (isNaN(dataLinkPointValue)) {
- dataLinkPointValue = 0;
- }
- value.push([dataLinkPointValue, timestamp]);
- }
- }
- result['${' + expression + '}'] = value;
- return result;
- },
- /**
- * add missing points, with zero value, to series
- *
- * @param {object} dataLinks
- * @param {number} length
- */
- adjustData: function(dataLinks, length) {
- //series with full data taken as original
- var original = [];
- var substituteValue = null;
- for (var i in dataLinks) {
- if (dataLinks[i].length === length) {
- original = dataLinks[i];
- break;
- }
- }
- original.forEach(function(point, index) {
- for (var i in dataLinks) {
- if (!dataLinks[i][index] || dataLinks[i][index][1] !== point[1]) {
- dataLinks[i].splice(index, 0, [substituteValue, point[1]]);
- }
- }
- }, this);
- },
- /**
- * make GET call to server in order to fetch service-component metrics
- * @param {object} request
- * @returns {$.ajax}
- */
- getServiceComponentMetrics: function (request) {
- return App.ajax.send({
- name: 'widgets.serviceComponent.metrics.get',
- sender: this,
- data: {
- serviceName: request.service_name,
- componentName: request.component_name,
- metricPaths: this.addTimeProperties(request.metric_paths).join(',')
- },
- success: 'getMetricsSuccessCallback'
- });
- },
- /**
- * make GET call to server in order to fetch host-component metrics
- * @param {object} request
- * @returns {$.ajax}
- */
- getHostComponentMetrics: function (request) {
- return App.ajax.send({
- name: 'widgets.hostComponent.metrics.get',
- sender: this,
- data: {
- componentName: request.component_name,
- metricPaths: this.addTimeProperties(request.metric_paths).join(','),
- hostComponentCriteria: this.computeHostComponentCriteria(request)
- },
- success: 'getHostComponentMetricsSuccessCallback'
- });
- },
- /**
- * add time properties
- * @param {Array} metricPaths
- * @returns {Array} result
- */
- addTimeProperties: function (metricPaths) {
- var toSeconds = Math.round(App.dateTime() / 1000);
- var fromSeconds = toSeconds - this.get('timeRange');
- var step = this.get('timeStep');
- var result = [];
- metricPaths.forEach(function (metricPath) {
- result.push(metricPath + '[' + fromSeconds + ',' + toSeconds + ',' + step + ']');
- }, this);
- return result;
- },
- /**
- * @type {Em.View}
- * @class
- */
- graphView: App.ChartLinearTimeView.extend({
- noTitleUnderGraph: true,
- inWidget: true,
- description: function () {
- return this.get('parentView.content.description');
- }.property('parentView.content.description'),
- isPreview: function () {
- return this.get('parentView.isPreview');
- }.property('parentView.isPreview'),
- displayUnit: function () {
- return this.get('parentView.content.properties.display_unit');
- }.property('parentView.content.properties.display_unit'),
- /**
- * set custom time range for graph widget
- */
- setTimeRange: function () {
- if (this.get('isPopup')) {
- this.set('parentView.customTimeRange', this.get('timeUnitSeconds'));
- } else {
- this.set('parentView.customTimeRange', null);
- }
- }.observes('isPopup', 'timeUnitSeconds'),
- /**
- * graph height
- * @type {number}
- */
- height: 95,
- /**
- * @type {string}
- */
- id: function () {
- return 'widget_'+ this.get('parentView.content.id') + '_graph';
- }.property('parentView.content.id'),
- /**
- * @type {string}
- */
- renderer: function () {
- return this.get('parentView.content.properties.graph_type') === 'STACK' ? 'area' : 'line';
- }.property('parentView.content.properties.graph_type'),
- title: function () {
- return this.get('parentView.content.widgetName');
- }.property('parentView.content.widgetName'),
- transformToSeries: function (seriesData) {
- var seriesArray = [];
- seriesData.forEach(function (_series) {
- seriesArray.push(this.transformData(_series.data, _series.name));
- }, this);
- return seriesArray;
- },
- loadData: function () {
- var self = this;
- Em.run.next(function () {
- self._refreshGraph(self.get('parentView.data'))
- });
- },
- didInsertElement: function () {
- this.loadData();
- var self = this;
- Em.run.next(function () {
- if (self.get('isPreview')) {
- App.tooltip(this.$("[rel='ZoomInTooltip']"), 'disable');
- } else {
- App.tooltip(this.$("[rel='ZoomInTooltip']"), {placement : 'left'});
- }
- });
- }.observes('parentView.data')
- })
- });
|