/*
* RHQ Management Platform
* Copyright (C) 2005-2008 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.enterprise.agent.promptcmd;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import mazz.i18n.Msg;
import org.rhq.enterprise.agent.AgentMain;
import org.rhq.enterprise.agent.StringUtil;
import org.rhq.enterprise.agent.AgentManagement;
import org.rhq.enterprise.agent.i18n.AgentI18NFactory;
import org.rhq.enterprise.agent.i18n.AgentI18NResourceKeys;
/**
* Displays the current metrics emitted by the agent itself.
*
* @author John Mazzitelli
*/
public class MetricsPromptCommand implements AgentPromptCommand {
private static final Msg MSG = AgentI18NFactory.getMsg();
/**
* @see AgentPromptCommand#getPromptCommandString()
*/
public String getPromptCommandString() {
return MSG.getMsg(AgentI18NResourceKeys.METRICS);
}
/**
* @see AgentPromptCommand#execute(AgentMain, String[])
*/
public boolean execute(AgentMain agent, String[] args) {
PrintWriter out = agent.getOut();
// There are other, easier ways to do this, but I want to go through the JMX interface.
// Since this is the interface used by the agent plugin to get metric data, this prompt
// command can be used to verify the exact data the agent plugin is getting.
AgentManagement agent_mbean = agent.getAgentManagementMBean();
if (agent_mbean != null) {
try {
MBeanServer the_mbs = agent_mbean.getMBeanServer();
displayMetrics(agent_mbean.getObjectName(), out, the_mbs);
} catch (Exception e) {
out.println(MSG.getMsg(AgentI18NResourceKeys.METRICS_EXCEPTION, e));
}
} else {
out.println(MSG.getMsg(AgentI18NResourceKeys.METRICS_NO_SERVICES));
}
return true;
}
/**
* Queries all the agent management MBean attributes and displays them.
*
* @param object_name the name of the management MBean
* @param out the output to write the information
* @param the_mbs the MBeanServer where the management MBean services are
*
* @throws Exception
*/
private void displayMetrics(ObjectName object_name, PrintWriter out, MBeanServer the_mbs) throws Exception {
// get all the attributes the management MBean exposes and then ask for all their values
MBeanInfo mbeaninfo = the_mbs.getMBeanInfo(object_name);
MBeanAttributeInfo[] attrib_infos = mbeaninfo.getAttributes();
String[] attrib_names = new String[attrib_infos.length];
for (int i = 0; i < attrib_infos.length; i++) {
attrib_names[i] = attrib_infos[i].getName();
}
HashMap<String, Object> name_value_pairs = new HashMap<String, Object>();
AttributeList attribs = the_mbs.getAttributes(object_name, attrib_names);
for (Iterator iter = attribs.iterator(); iter.hasNext();) {
Attribute attrib = (Attribute) iter.next();
String name = attrib.getName();
Object value = attrib.getValue();
// some attributes we do not want to display; skip them as we find them
if (name.equals("AgentConfiguration")) {
continue; // skip because this makes the output too big and noisy - user can use getconfig to see this data
}
// we might want to format some attributes into more human readable forms
if (name.equals("CurrentTime")) {
value = new Date(((Long) value).longValue());
} else if (name.equals("Uptime")) {
value = formatSeconds(((Long) value).longValue());
} else if (name.equals("JVMTotalMemory") || name.equals("JVMFreeMemory")) {
//value = formatBytes(((Long) value).longValue());
continue;
}
name_value_pairs.put(name, value);
}
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
name_value_pairs.put("Memory - Heap",
"Used: " + formatBytes(memoryBean.getHeapMemoryUsage().getUsed())
+ ", Committed: " + formatBytes(memoryBean.getHeapMemoryUsage().getCommitted())
+ ", Max: " + formatBytes(memoryBean.getHeapMemoryUsage().getMax()));
name_value_pairs.put("Memory - Non Heap",
"Used: " + formatBytes(memoryBean.getNonHeapMemoryUsage().getUsed())
+ ", Committed: " + formatBytes(memoryBean.getNonHeapMemoryUsage().getCommitted())
+ ", Max: " + formatBytes(memoryBean.getNonHeapMemoryUsage().getMax()));
out.println(MSG.getMsg(AgentI18NResourceKeys.METRICS_HEADER));
out.println(StringUtil.justifyKeyValueStrings(name_value_pairs));
return;
}
/**
* Formats the given time duration (specified in seconds) into seconds, minutes, hours or days as appropriate.
*
* @param seconds the time duration to format
*
* @return the number of seconds in string form and in the most appropriate units (seconds, minutes, hours, days)
*/
private String formatSeconds(long seconds) {
String ret_val = null;
if (seconds >= (60 * 60 * 24)) {
ret_val = String.format("%.1f ", new Object[] { ((float) seconds / (60L * 60 * 24)) })
+ MSG.getMsg(AgentI18NResourceKeys.UNITS_DAYS);
} else if (seconds >= (60 * 60)) {
ret_val = String.format("%.1f ", new Object[] { ((float) seconds / (60L * 60)) })
+ MSG.getMsg(AgentI18NResourceKeys.UNITS_HOURS);
} else if (seconds >= (60)) {
ret_val = String.format("%.1f ", new Object[] { ((float) seconds / (60L)) })
+ MSG.getMsg(AgentI18NResourceKeys.UNITS_MINUTES);
}
if (ret_val != null) {
ret_val += " (" + seconds + ")";
} else {
ret_val = seconds + " " + MSG.getMsg(AgentI18NResourceKeys.UNITS_SECONDS);
}
return ret_val;
}
/**
* Formats a count of bytes into KB, MB, GB or TB as appropriate.
*
* @param bytes
*
* @return the number of bytes in string form and in the most appropriate units
*/
private String formatBytes(long bytes) {
String ret_str = "";
// we only understand KB, MB, GB and TB. Anything outside that range is returned in bytes
// KB=1,000 : MB=1,000,000 : GB=1,000,000,000 : TB=1,000,000,000,000
if ((bytes >= 1000) && (bytes <= 999999999999999L)) {
if (bytes < 1000000) {
ret_str += String.format("%.2f", new Object[] { (float) bytes / 1000L }) + " KB";
} else if (bytes < 1000000000) {
ret_str += String.format("%.2f", new Object[] { (float) bytes / 1000000L }) + " MB";
} else if (bytes < 1000000000000L) {
ret_str += String.format("%.2f", new Object[] { (float) bytes / 1000000L }) + " GB";
} else {
ret_str += String.format("%.2f", new Object[] { (float) bytes / 1000000000L }) + " TB";
}
//ret_str += " (" + bytes + ")";
} else {
ret_str += bytes;
}
return ret_str;
}
/**
* @see AgentPromptCommand#getSyntax()
*/
public String getSyntax() {
return MSG.getMsg(AgentI18NResourceKeys.METRICS_SYNTAX);
}
/**
* @see AgentPromptCommand#getHelp()
*/
public String getHelp() {
return MSG.getMsg(AgentI18NResourceKeys.METRICS_HELP);
}
/**
* @see AgentPromptCommand#getDetailedHelp()
*/
public String getDetailedHelp() {
return MSG.getMsg(AgentI18NResourceKeys.METRICS_DETAILED_HELP);
}
}