diff options
| author | Shireesh Anjal <shireesh@gluster.com> | 2011-07-26 22:41:27 +0530 |
|---|---|---|
| committer | Shireesh Anjal <shireesh@gluster.com> | 2011-07-26 22:42:10 +0530 |
| commit | 1a02f33dc4e8315a62843a331c8f1c1af05b3861 (patch) | |
| tree | c1cc23543f5ab35948b250d9cdf9166cf6389779 /src | |
| parent | a61cfcf7e36ba89deff92b09a6041469f04acefe (diff) | |
Story #29 - Memory Usage Graph
Diffstat (limited to 'src')
5 files changed, 362 insertions, 12 deletions
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java index ee29c353..9042dc9a 100644 --- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java +++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java @@ -92,6 +92,21 @@ public class GlusterServersClient extends AbstractClient { return fetchSubResource(serverName + "/" + RESTConstants.RESOURCE_STATISTICS, queryParams, ServerStats.class); } + public ServerStats getMemoryStats(String serverName, String period) { + MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); + queryParams.add(RESTConstants.QUERY_PARAM_TYPE, RESTConstants.STATISTICS_TYPE_MEMORY); + queryParams.add(RESTConstants.QUERY_PARAM_PERIOD, period); + return fetchSubResource(serverName + "/" + RESTConstants.RESOURCE_STATISTICS, queryParams, ServerStats.class); + } + + public ServerStats getNetworkStats(String serverName, String networkInterface, String period) { + MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); + queryParams.add(RESTConstants.QUERY_PARAM_TYPE, RESTConstants.STATISTICS_TYPE_MEMORY); + queryParams.add(RESTConstants.QUERY_PARAM_PERIOD, period); + queryParams.add(RESTConstants.QUERY_PARAM_INTERFACE, networkInterface); + return fetchSubResource(serverName + "/" + RESTConstants.RESOURCE_STATISTICS, queryParams, ServerStats.class); + } + public ServerStats getAggregatedCpuStats(String period) { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add(RESTConstants.QUERY_PARAM_TYPE, RESTConstants.STATISTICS_TYPE_CPU); diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ChartUtil.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ChartUtil.java new file mode 100644 index 00000000..a7559f9e --- /dev/null +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ChartUtil.java @@ -0,0 +1,294 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> + * This file is part of Gluster Management Console. + * + * Gluster Management Console is free software; you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Gluster Management Console is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * <http://www.gnu.org/licenses/>. + *******************************************************************************/ +package com.gluster.storage.management.gui.utils; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.birt.chart.util.CDateTime; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.forms.events.HyperlinkAdapter; +import org.eclipse.ui.forms.events.HyperlinkEvent; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.Hyperlink; + +import com.gluster.storage.management.client.GlusterServersClient; +import com.gluster.storage.management.core.constants.GlusterConstants; +import com.gluster.storage.management.core.model.Cluster; +import com.gluster.storage.management.core.model.ServerStats; +import com.gluster.storage.management.core.model.ServerStatsRow; +import com.gluster.storage.management.gui.Activator; +import com.gluster.storage.management.gui.preferences.PreferenceConstants; +import com.gluster.storage.management.gui.views.ClusterSummaryView.ChartPeriodLinkListener; +import com.ibm.icu.util.Calendar; + +/** + * + */ +public class ChartUtil { + private static final ChartUtil instance = new ChartUtil(); + private static final GUIHelper guiHelper = GUIHelper.getInstance(); + private static final int CHART_WIDTH = 350; + + private ChartUtil() { + } + + public static ChartUtil getInstance() { + return instance; + } + + public Composite createAreaChartSection(FormToolkit toolkit, Composite section, ServerStats stats, + int dataColumnIndex, String unit, String timestampFormat, ChartPeriodLinkListener listener, double maxValue) { + List<Calendar> timestamps = new ArrayList<Calendar>(); + List<Double> data = new ArrayList<Double>(); + + extractChartData(stats, timestamps, data, dataColumnIndex); + + if (timestamps.size() == 0) { + toolkit.createLabel(section, + "Server statistics not available!\n Check if all services are running properly on the cluster servers."); + return null; + } + + createAreaChart(section, timestamps.toArray(new Calendar[0]), data.toArray(new Double[0]), unit, + timestampFormat, maxValue); + + // Calendar[] timestamps = new Calendar[] { new CDateTime(1000l*1310468100), new CDateTime(1000l*1310468400), + // new CDateTime(1000l*1310468700), + // new CDateTime(1000l*1310469000), new CDateTime(1000l*1310469300), new CDateTime(1000l*1310469600), new + // CDateTime(1000l*1310469900), + // new CDateTime(1000l*1310470200), new CDateTime(1000l*1310470500), new CDateTime(1000l*1310470800), new + // CDateTime(1000l*1310471100), + // new CDateTime(1000l*1310471400), new CDateTime(1000l*1310471700), new CDateTime(1000l*1310472000), new + // CDateTime(1000l*1310472300), + // new CDateTime(1000l*1310472600), new CDateTime(1000l*1310472900), new CDateTime(1000l*1310473200), new + // CDateTime(1000l*1310473500), + // new CDateTime(1000l*1310473800) }; + // + // Double[] values = new Double[] { 10d, 11.23d, 17.92d, 18.69d, 78.62d, 89.11d, 92.43d, 89.31d, 57.39d, 18.46d, + // 10.44d, 16.28d, 13.51d, 17.53d, 12.21, 20d, 21.43d, 16.45d, 14.86d, 15.27d }; + // createLineChart(section, timestamps, values, "%"); + createChartLinks(toolkit, section, 4, listener); + return section; + } + + private ChartViewerComposite createAreaChart(Composite section, Calendar timestamps[], Double values[], + String unit, String timestampFormat, double maxValue) { + ChartViewerComposite chartViewerComposite = new ChartViewerComposite(section, SWT.NONE, timestamps, values, + unit, timestampFormat, maxValue); + GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); + data.widthHint = CHART_WIDTH; + data.heightHint = 250; + data.verticalAlignment = SWT.CENTER; + chartViewerComposite.setLayoutData(data); + return chartViewerComposite; + } + + private void extractChartData(ServerStats stats, List<Calendar> timestamps, List<Double> data, int dataColumnIndex) { + for (ServerStatsRow row : stats.getRows()) { + Double cpuUsage = row.getUsageData().get(dataColumnIndex); + if (!cpuUsage.isNaN()) { + timestamps.add(new CDateTime(row.getTimestamp() * 1000)); + data.add(cpuUsage); + } + } + } + + private Composite createChartLinks(FormToolkit toolkit, Composite section, int columnCount, + ChartPeriodLinkListener listener) { + GridLayout layout = new org.eclipse.swt.layout.GridLayout(columnCount, false); + layout.marginBottom = 0; + layout.marginTop = 0; + layout.marginLeft = (CHART_WIDTH - (50 * columnCount)) / 2; + Composite graphComposite = toolkit.createComposite(section, SWT.NONE); + graphComposite.setLayout(layout); + GridData data = new GridData(SWT.FILL, SWT.FILL, false, false); + data.widthHint = CHART_WIDTH; + graphComposite.setLayoutData(data); + + createStatsLink(toolkit, listener, graphComposite, "1 day", GlusterConstants.STATS_PERIOD_1DAY); + createStatsLink(toolkit, listener, graphComposite, "1 week", GlusterConstants.STATS_PERIOD_1WEEK); + createStatsLink(toolkit, listener, graphComposite, "1 month", GlusterConstants.STATS_PERIOD_1MONTH); + createStatsLink(toolkit, listener, graphComposite, "1 year", GlusterConstants.STATS_PERIOD_1YEAR); + + return graphComposite; + } + + private void createStatsLink(FormToolkit toolkit, ChartPeriodLinkListener listener, Composite parent, String label, + String statsPeriod) { + Hyperlink link1 = toolkit.createHyperlink(parent, label, SWT.NONE); + link1.addHyperlinkListener(listener.getInstance(statsPeriod)); + if (listener.getStatsPeriod().equals(statsPeriod)) { + link1.setEnabled(false); + } + } + + public abstract class ChartPeriodLinkListener extends HyperlinkAdapter { + protected String statsPeriod; + protected String unit; + protected int columnCount; + protected double maxValue; + protected Cluster cluster; + protected FormToolkit toolkit; + protected String serverName; + + public String getStatsPeriod() { + return this.statsPeriod; + } + + public ChartPeriodLinkListener(Cluster cluster, String serverName, String statsPeriod, String unit, + double maxValue, int columnCount, FormToolkit toolkit) { + this.cluster = cluster; + this.serverName = serverName; + this.statsPeriod = statsPeriod; + this.unit = unit; + this.columnCount = columnCount; + this.maxValue = maxValue; + this.cluster = cluster; + this.toolkit = toolkit; + } + + public ChartPeriodLinkListener(String serverName, String statsPeriod, FormToolkit toolkit) { + this.statsPeriod = statsPeriod; + this.serverName = serverName; + this.toolkit = toolkit; + } + + @Override + public void linkActivated(HyperlinkEvent e) { + super.linkActivated(e); + // GlusterDataModelManager.getInstance().initializeAlerts(cluster); + Composite section = ((Hyperlink) e.getSource()).getParent().getParent(); + ServerStats stats = fetchStats(serverName); + refreshChartSection(toolkit, section, stats, statsPeriod, unit, maxValue, columnCount, this); + } + + public abstract ChartPeriodLinkListener getInstance(String statsPeriod); + + protected abstract ServerStats fetchStats(String serverName); + } + + public class CpuChartPeriodLinkListener extends ChartPeriodLinkListener { + private CpuChartPeriodLinkListener(Cluster cluster, String serverName, String statsPeriod, String unit, + double maxValue, int columnCount, FormToolkit toolkit) { + super(cluster, serverName, statsPeriod, unit, maxValue, columnCount, toolkit); + } + + @Override + protected ServerStats fetchStats(String serverName) { + IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); + preferenceStore.setValue(PreferenceConstants.P_CPU_CHART_PERIOD, statsPeriod); + ServerStats stats; + if (serverName == null) { + stats = new GlusterServersClient().getAggregatedCpuStats(statsPeriod); + cluster.setAggregatedCpuStats(stats); + } else { + stats = new GlusterServersClient().getCpuStats(serverName, statsPeriod); + } + return stats; + } + + @Override + public ChartPeriodLinkListener getInstance(String statsPeriod) { + return new CpuChartPeriodLinkListener(cluster, serverName, statsPeriod, "%", 100, 4, toolkit); + } + } + + public class MemoryChartPeriodLinkListener extends ChartPeriodLinkListener { + public MemoryChartPeriodLinkListener(String serverName, String statsPeriod, FormToolkit toolkit) { + super(serverName, statsPeriod, toolkit); + } + + private MemoryChartPeriodLinkListener(Cluster cluster, String serverName, String statsPeriod, String unit, + double maxValue, int columnCount, FormToolkit toolkit) { + super(cluster, serverName, statsPeriod, unit, maxValue, columnCount, toolkit); + } + + @Override + protected ServerStats fetchStats(String serverName) { + IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); + preferenceStore.setValue(PreferenceConstants.P_MEM_CHART_PERIOD, statsPeriod); + ServerStats stats = new GlusterServersClient().getMemoryStats(serverName, statsPeriod); + return stats; + } + + @Override + public ChartPeriodLinkListener getInstance(String statsPeriod) { + return new MemoryChartPeriodLinkListener(cluster, serverName, statsPeriod, "%", 100, 4, toolkit); + } + } + + public class NetworkChartPeriodLinkListener extends ChartPeriodLinkListener { + private NetworkChartPeriodLinkListener(Cluster cluster, String serverName, String statsPeriod, String unit, + double maxValue, int columnCount, FormToolkit toolkit) { + super(cluster, serverName, statsPeriod, unit, maxValue, columnCount, toolkit); + } + + @Override + protected ServerStats fetchStats(String serverName) { + IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); + preferenceStore.setValue(PreferenceConstants.P_NETWORK_CHART_PERIOD, statsPeriod); + ServerStats stats; + if (serverName == null) { + stats = new GlusterServersClient().getAggregatedNetworkStats(statsPeriod); + cluster.setAggregatedNetworkStats(stats); + } else { + stats = new GlusterServersClient().getNetworkStats(serverName, "eth0", statsPeriod); + } + + return stats; + } + + @Override + public ChartPeriodLinkListener getInstance(String statsPeriod) { + return new NetworkChartPeriodLinkListener(cluster, serverName, statsPeriod, "KiB/s", -1d, 4, toolkit); + } + } + + private void refreshChartSection(FormToolkit toolkit, Composite section, ServerStats stats, String statsPeriod, + String unit, double maxValue, int columnCount, ChartPeriodLinkListener linkListener) { + for (Control control : section.getChildren()) { + if (!control.isDisposed()) { + control.dispose(); + } + } + List<Calendar> timestamps = new ArrayList<Calendar>(); + List<Double> data = new ArrayList<Double>(); + extractChartData(stats, timestamps, data, 2); + createAreaChart(section, timestamps.toArray(new Calendar[0]), data.toArray(new Double[0]), unit, + getTimestampFormatForPeriod(statsPeriod), maxValue); + createChartLinks(toolkit, section, columnCount, linkListener); + section.layout(); + } + + public String getTimestampFormatForPeriod(String statsPeriod) { + if (statsPeriod.equals(GlusterConstants.STATS_PERIOD_1DAY)) { + return "HH:mm"; + } else if (statsPeriod.equals(GlusterConstants.STATS_PERIOD_1WEEK)) { + return "dd-MMM HH:mm"; + } else { + return "dd-MMM"; + } + } +} diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java index 492b51f3..b2804fab 100644 --- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java +++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/GlusterServerSummaryView.java @@ -63,6 +63,7 @@ import com.gluster.storage.management.gui.IImageKeys; import com.gluster.storage.management.gui.NetworkInterfaceTableLabelProvider; import com.gluster.storage.management.gui.preferences.PreferenceConstants; import com.gluster.storage.management.gui.toolbar.GlusterToolbarManager; +import com.gluster.storage.management.gui.utils.ChartUtil; import com.gluster.storage.management.gui.utils.ChartViewerComposite; import com.gluster.storage.management.gui.utils.GUIHelper; import com.ibm.icu.util.Calendar; @@ -129,17 +130,25 @@ public class GlusterServerSummaryView extends ViewPart { } private void createMemoryUsageSection() { + IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); + String memStatsPeriod = preferenceStore.getString(PreferenceConstants.P_MEM_CHART_PERIOD); + + ServerStats stats; + try { + stats = new GlusterServersClient().getMemoryStats(server.getName(), memStatsPeriod); + // in case of CPU usage, there are three elements in usage data: user, system and total. we use total. + //createAreaChartSection(stats, "Memory Usage", 2, "%"); + } catch(Exception e) { + logger.error("Couldn't fetch CPU usage statistics for server [" + server.getName() + "]", e); + return; + } + Composite section = guiHelper.createSection(form, toolkit, "Memory Usage", null, 1, false); - Calendar[] timestamps = new Calendar[] { new CDateTime(1000l*1310468100), new CDateTime(1000l*1310468400), new CDateTime(1000l*1310468700), - new CDateTime(1000l*1310469000), new CDateTime(1000l*1310469300), new CDateTime(1000l*1310469600), new CDateTime(1000l*1310469900), - new CDateTime(1000l*1310470200), new CDateTime(1000l*1310470500), new CDateTime(1000l*1310470800), new CDateTime(1000l*1310471100), - new CDateTime(1000l*1310471400), new CDateTime(1000l*1310471700), new CDateTime(1000l*1310472000), new CDateTime(1000l*1310472300), - new CDateTime(1000l*1310472600), new CDateTime(1000l*1310472900), new CDateTime(1000l*1310473200), new CDateTime(1000l*1310473500), - new CDateTime(1000l*1310473800) }; - //Double[] values = new Double[] { 10d, 11.23d, 17.92d, 18.69d, 78.62d, 89.11d, 92.43d, 20.31d, 19.63d, 18.46d, 10.44d, 16.28d, 13.51d, 17.53d, 12.21, 20d, 40d, 10d, 90d, 40d }; - Double[] values = new Double[] { 35d, 34.23d, 37.92d, 28.69d, 38.62d, 39.11d, 38.46d, 30.44d, 36.28d, 72.43d, 79.31d, 77.39d, 33.51d, 37.53d, 32.21, 30d, 31.43d, 36.45d, 34.86d, 35.27d }; - createAreaChart(section, timestamps, values, "%"); - createChartLinks(section, 4); + // in case of CPU usage, there are three elements in usage data: user, system and total. we use total. + ChartUtil chartUtil = ChartUtil.getInstance(); + chartUtil.createAreaChartSection(toolkit, section, stats, 0, "%", chartUtil + .getTimestampFormatForPeriod(memStatsPeriod), + chartUtil.new MemoryChartPeriodLinkListener(server.getName(), memStatsPeriod, toolkit), 100); } private void createNetworkUsageSection() { diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/AbstractStatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/AbstractStatsFactory.java index 820cc542..b6e95270 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/AbstractStatsFactory.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/AbstractStatsFactory.java @@ -51,7 +51,7 @@ public abstract class AbstractStatsFactory implements StatsFactory { return stats; } catch(Exception e) { // server might be offline - continue with next one - logger.warn("Couldn't fetch CPU stats from server [" + serverName + "]!", e); + logger.warn("Couldn't fetch stats from server [" + serverName + "]!", e); if(removeServerOnError) { serverNames.remove(serverName); } diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/MemoryStatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/MemoryStatsFactory.java index 65f4e44e..fcbf43d5 100644 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/MemoryStatsFactory.java +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/MemoryStatsFactory.java @@ -18,19 +18,51 @@ *******************************************************************************/ package com.gluster.storage.management.server.utils; +import java.util.List; + import org.springframework.stereotype.Component; +import com.gluster.storage.management.core.model.ServerStats; +import com.gluster.storage.management.core.model.ServerStatsRow; + /** * */ @Component public class MemoryStatsFactory extends AbstractStatsFactory { - private static final String MEM_STATS_SCRIPT = "get_rrd_mem_details.py"; + private static final String MEM_STATS_SCRIPT = "get_rrd_memory_details.py"; @Override public String getStatsScriptName() { return MEM_STATS_SCRIPT; } + @Override + public ServerStats fetchStats(String serverName, String period, String... args) { + ServerStats stats = super.fetchStats(serverName, period, args); + + // stats returned by rrd script contains five columns - user, free, cache, buffer, total + // out of this, the "user" memory includes cached and buffer. We remove them to get the + // actual memory used by "user" + for(ServerStatsRow row : stats.getRows()) { + List<Double> data = row.getUsageData(); + Double user = data.get(0); + Double free = data.get(1); + Double cache = data.get(2); + Double buffer = data.get(3); + Double total = data.get(4); + + Double actualUser = user - cache - buffer; + + // convert all figures from bytes to percentages + data.set(0, (actualUser * 100) / total); + data.set(1, (free * 100) / total); + data.set(2, (cache * 100) / total); + data.set(3, (buffer * 100) / total); + data.set(4, (total * 100) / total); + } + + return stats; + } } |
