Mercurial > hg > thermostat-ng > web-client
view src/app/components/jvm-info/jvm-memory/jvm-memory.controller.js @ 271:671cfc1d001d
Streamline jvm-memory metric conversion filters
Reviewed-by: jkang
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-October/025371.html
author | Andrew Azores <aazores@redhat.com> |
---|---|
date | Wed, 25 Oct 2017 11:51:03 -0400 |
parents | 4023b79e4d58 |
children | b35a283eb016 |
line wrap: on
line source
/** * Copyright 2012-2017 Red Hat, Inc. * * Thermostat is distributed under the GNU General Public License, * version 2 or any later version (with a special exception described * below, commonly known as the "Classpath Exception"). * * A copy of GNU General Public License (GPL) is included in this * distribution, in the file COPYING. * * Linking Thermostat code with other modules is making a combined work * based on Thermostat. Thus, the terms and conditions of the GPL * cover the whole combination. * * As a special exception, the copyright holders of Thermostat give you * permission to link this code with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on Thermostat code. If you modify Thermostat, you may * extend this exception to your version of the software, but you are * not obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ import 'c3'; import _ from 'lodash'; import services from 'shared/services/services.module.js'; import filters from 'shared/filters/filters.module.js'; import service from './jvm-memory.service.js'; class JvmMemoryController { constructor ($stateParams, $interval, jvmMemoryService, dateFilter, DATE_FORMAT, metricToNumberFilter, scaleBytesService, sanitizeService, $translate) { 'ngInject'; this.jvmId = $stateParams.jvmId; this._interval = $interval; this._jvmMemoryService = jvmMemoryService; this._sanitizeService = sanitizeService; this._translate = $translate; this._dateFilter = dateFilter; this._dateFormat = DATE_FORMAT; this._metricToNumber = metricToNumberFilter; this._scaleBytes = scaleBytesService; this.metaspaceSnapshotData = { used: 0, total: 0 }; this._metaspaceData = { timestamps: [], used: [], capacity: [] }; this.metaspaceSeriesData = { xData: ['timestamp'], yData: ['memory'] }; this.metaspaceBarConfig = { units: 'B' }; $translate(['jvmMemory.X_AXIS_LABEL', 'jvmMemory.Y_AXIS_LABEL']).then(translations => { this._xAxisLabel = translations['jvmMemory.X_AXIS_LABEL']; this._yAxisLabel = translations['jvmMemory.Y_AXIS_LABEL']; this.metaspaceLineConfig = { chartId: 'metaspaceLineChart', units: 'B', axis: { x: { show: true, type: 'timeseries', label: { text: this._xAxisLabel, position: 'outer-center' }, tick : { format: timestamp => this._dateFilter(timestamp, this._dateFormat.time.medium), count: 5, fit: false } }, y: { show: true, min: 0, padding: 0, tick: 10, label: { text: this._yAxisLabel, position: 'outer-middle' } } } }; }); this.spaceBarConfigs = []; this._generationData = new Map(); this.generationSnapshotData = {}; this.generationSeriesData = {}; this.generationLineConfigs = new Map(); this._refreshRate = 2000; this._dataAgeLimit = 10 * 60 * 1000; this._lastUpdate = this._getCurrentTimestamp(); } getLineConfig (genIndex, spaceIndex) { let key = `line-gen-${genIndex}-space-${spaceIndex}`; if (!this.generationLineConfigs.has(key)) { let config = { chartId: key, units: 'B', axis: { x: { show: true, type: 'timeseries', label: { text: this._xAxisLabel, position: 'outer-center' }, tick : { format: timestamp => this._dateFilter(timestamp, this._dateFormat.time.medium), count: 5, fit: false } }, y: { show: true, min: 0, padding: 0, tick: 10, label: { text: this._yAxisLabel, position: 'outer-middle' } } } }; this.generationLineConfigs.set(key, config); } return this.generationLineConfigs.get(key); } $onInit () { this._start(); } $onDestroy () { this._stop(); } _start () { this._stop(); this._loadHistoricalData(); this._refresh = this._interval(() => this._update(), this.refreshRate); } _stop () { if (angular.isDefined(this._refresh)) { this._interval.cancel(this._refresh); delete this._refresh; } } set refreshRate (val) { this._stop(); this._refreshRate = parseInt(val); if (this._refreshRate > 0) { this._start(); } } get refreshRate () { return this._refreshRate.toString(); } set dataAgeLimit (val) { this._dataAgeLimit = parseInt(val); this._loadHistoricalData(); } get dataAgeLimit () { return this._dataAgeLimit.toString(); } multichartMetaspace () { return new Promise(resolve => this._jvmMemoryService.getSnapshot(this.jvmId).then(resp => resolve(this.convertMemStat(resp.metaspaceUsed)) ) ); } multichartSpace (generationIndex, spaceIndex) { return new Promise(resolve => this._jvmMemoryService.getSnapshot(this.jvmId).then(resp => { generationIndex = parseInt(generationIndex); spaceIndex = parseInt(spaceIndex); let generation = resp.generations[generationIndex]; let space = generation.spaces[spaceIndex]; resolve(this.convertMemStat(space.used)); }) ); } _loadHistoricalData () { this._clearData(); let now = this._getCurrentTimestamp(); let limit = now - this._dataAgeLimit; this._jvmMemoryService.getJvmMemory(this.jvmId, limit) .then(resp => this._processUpdates(resp)); } _clearData () { this._metaspaceData.timestamps = []; this._metaspaceData.used = []; this._metaspaceData.capacity = []; this._generationData.clear(); } _update () { this._jvmMemoryService.getJvmMemory(this.jvmId, this._lastUpdate) .then(resp => this._processUpdates(resp)); } _processUpdates (resp) { this._lastUpdate = this._getCurrentTimestamp(); let keys = []; resp.forEach(update => { for (let i = 0; i < update.generations.length; i++) { update.generations[i].index = i; } let timestamp = this._metricToNumber(update.timeStamp); let metaspaceUsed = this.convertMemStat(update.metaspaceUsed); let metaspaceCapacity = this.convertMemStat(update.metaspaceCapacity); this._metaspaceData.timestamps.push(timestamp); this._metaspaceData.used.push(metaspaceUsed); this._metaspaceData.capacity.push(metaspaceCapacity); update.generations.forEach(generation => { generation.spaces.forEach(space => { let key = this._getKey(generation.index, space.index); keys.push(key); if (!this._generationData.has(key)) { this._generationData.set(key, { timestamps: [], used: [], capacity: [] }); } let used = this.convertMemStat(space.used); let capacity = this.convertMemStat(space.capacity); let data = this._generationData.get(key); data.timestamps.push(timestamp); data.used.push(used); data.capacity.push(capacity); }); }); }); this._trimData(); if (resp.length > 0) { this._updateLineCharts(keys); this._updateBarCharts(resp[0]); } } _trimData () { let now = this._getCurrentTimestamp(); let limit = now - this._dataAgeLimit; let metaspaceSpliceCount = 0; for (; metaspaceSpliceCount < this._metaspaceData.timestamps.length; metaspaceSpliceCount++) { let sample = this._metaspaceData.timestamps[metaspaceSpliceCount]; if (sample >= limit) { break; } } this._metaspaceData.timestamps.splice(0, metaspaceSpliceCount); this._metaspaceData.used.splice(0, metaspaceSpliceCount); this._metaspaceData.capacity.splice(0, metaspaceSpliceCount); this._generationData.forEach(sampleSet => { let sampleSpliceCount = 0; for (; sampleSpliceCount < sampleSet.timestamps.length; sampleSpliceCount++) { let sample = sampleSet.timestamps[sampleSpliceCount]; if (sample >= limit) { break; } } sampleSet.timestamps.splice(0, sampleSpliceCount); sampleSet.used.splice(0, sampleSpliceCount); sampleSet.capacity.splice(0, sampleSpliceCount); }); } _updateLineCharts (keys) { this.metaspaceSeriesData = { xData: ['timestamp'].concat(this._metaspaceData.timestamps), yData: ['memory'].concat(this._metaspaceData.used) }; keys.forEach(key => { this.generationSeriesData[key] = { xData: ['timestamp'].concat(this._generationData.get(key).timestamps), yData: ['memory'].concat(this._generationData.get(key).used) }; }); } _updateBarCharts (data) { let metaspaceScale = this._scaleBytes.format(_.last(this._metaspaceData.used)); this.metaspaceSnapshotData = { used: this.convertMemStat(_.last(this._metaspaceData.used), metaspaceScale.scale), total: this.convertMemStat(_.last(this._metaspaceData.capacity), metaspaceScale.scale) }; // re-assign chart config so that Angular picks up the change. If we only re-assign property values // on the same config object, those config updates are not detected and do not reflect in the charts. this.metaspaceBarConfig = { chartId: 'metaspaceBarChart', units: metaspaceScale.unit }; for (let i = 0; i < data.generations.length; i++) { let generation = data.generations[i]; let gen; if (this.generationSnapshotData.hasOwnProperty(i)) { gen = this.generationSnapshotData[i]; } else { gen = { index: generation.index, name: generation.name, collector: generation.collector, spaces: [] }; } for (let j = 0; j < generation.spaces.length; j++) { let space = generation.spaces[j]; let key = this._getKey(gen.index, space.index); let generationData = this._generationData.get(key); let latestUsed = _.last(generationData.used); let latestCapacity = _.last(generationData.capacity); let genScale = this._scaleBytes.format(latestUsed); if (gen.spaces.hasOwnProperty(space.index)) { gen.spaces[space.index].used = this.convertMemStat(latestUsed, genScale.scale); gen.spaces[space.index].total = this.convertMemStat(latestCapacity, genScale.scale); } else { gen.spaces[space.index] = { index: space.index, used: this.convertMemStat(latestUsed, genScale.scale), total: this.convertMemStat(latestCapacity, genScale.scale) }; } this._translate('jvmMemory.SPACE', { index: space.index }).then(chartTitle => { this.spaceBarConfigs[key] = { key: key, units: genScale.unit, title: chartTitle }; }); } this.generationSnapshotData[i] = gen; } } _getKey (genIndex, spaceIndex) { return `${genIndex}:${spaceIndex}`; } convertMemStat (stat, scale) { return _.ceil(this._metricToNumber(stat, scale)); } sanitize (str) { return this._sanitizeService.sanitize(str); } _getCurrentTimestamp () { return Date.now(); } } export default angular .module('jvmMemory.controller', [ 'patternfly', 'patternfly.charts', services, filters, service ]) .controller('JvmMemoryController', JvmMemoryController) .name;