Java tutorial
/* * Copyright (C) 2009-2015 Pivotal Software, Inc * * This program is is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package com.springsource.hq.plugin.tcserver.plugin; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.RuntimeMXBean; import java.net.MalformedURLException; import java.util.Properties; import java.util.Set; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.JMException; import javax.management.MBeanException; import javax.management.MBeanServerConnection; import javax.management.MalformedObjectNameException; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.ReflectionException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperic.hq.product.Metric; import org.hyperic.hq.product.MetricInvalidException; import org.hyperic.hq.product.MetricNotFoundException; import org.hyperic.hq.product.MetricUnreachableException; import org.hyperic.hq.product.MetricValue; import org.hyperic.hq.product.PluginException; import org.hyperic.hq.product.jmx.MxMeasurementPlugin; import org.hyperic.hq.product.jmx.MxUtil; import com.springsource.hq.plugin.tcserver.plugin.wrapper.JmxUtils; import com.springsource.hq.plugin.tcserver.plugin.wrapper.MxUtilJmxUtils; /** * The measurement plugin that handles the custom measurements. * */ public class TomcatMeasurementPlugin extends MxMeasurementPlugin { private static final String DEADLOCKED_DETECTION_COUNT = "deadlockedThreadCount"; private static final String PERCENT_UP_TIME_IN_GARBAGE_COLLECTION_METRIC_NAME = "percentUpTimeSpent"; private static final String PERCENT_ACTIVE_CONNECTIONS = "percentActiveConnections"; private static final String PERCENT_ALLOCATED_THREADS = "percentAllocatedThreads"; private static final String PERCENT_ACTIVE_THREADS = "percentActiveThreads"; private static final String HEAP_FREE_MEMORY = "HeapMemoryUsage.free"; private static final Log LOGGER = LogFactory.getLog(TomcatMeasurementPlugin.class); private final JmxUtils mxUtil; public TomcatMeasurementPlugin() { this(new MxUtilJmxUtils()); } TomcatMeasurementPlugin(JmxUtils jmxUtils) { this.mxUtil = jmxUtils; } private MBeanServerConnection getConnection(Properties config) throws PluginException, MetricUnreachableException { try { return mxUtil.getMBeanServer(config); } catch (MalformedURLException e) { String msg = "Malformed URL: [" + config.getProperty(mxUtil.getJmxUrlProperty()) + "]"; throw new PluginException(msg, e); } catch (IOException e) { String msg = "Can't connect to MBeanServer with url [" + config.getProperty(mxUtil.getJmxUrlProperty()) + "] and user [" + config.getProperty(MxUtil.PROP_JMX_USERNAME) + "]: " + e; throw new MetricUnreachableException(msg, e); } } private MetricValue percentUptimeInGarbageCollection(final MBeanServerConnection connection) throws MetricUnreachableException, MetricNotFoundException, PluginException { double percentCollectionTime = 0; try { long totalGcTime = getTotalGarbageCollectionTime(connection); long upTime = getJvmUptime(connection); if (upTime > 0) { percentCollectionTime = (double) totalGcTime / (double) upTime; } } catch (IllegalArgumentException e) { // Common occurrence of this can happen when the user is using // an IBM JVM. LOGGER.debug("Unable to retrieve metric " + PERCENT_UP_TIME_IN_GARBAGE_COLLECTION_METRIC_NAME + e.getMessage(), e); throw new MetricUnreachableException("Unable to retrieve metric " + PERCENT_UP_TIME_IN_GARBAGE_COLLECTION_METRIC_NAME + " - " + e.getMessage(), e); } return new MetricValue(percentCollectionTime * 100); } private int getDeadlockedThreadCount(MBeanServerConnection connection) throws MetricInvalidException, MetricUnreachableException { int deadlockCount = 0; try { // in version 1.6+ there is a findDeadlockedThreads method long[] deadlocks; try { deadlocks = (long[]) connection.invoke(new ObjectName("java.lang:type=Threading"), "findDeadlockedThreads", null, null); } catch (MalformedObjectNameException e) { throw new MetricInvalidException("Error querying for deadlock thread mbean: " + e.getMessage(), e); } catch (JMException e) { LOGGER.debug("Method 'findDeadlockedThreads' for objectname 'java.lang:type=Threading'" + "was not found. Trying method findMonitorDeadlockedThreads...", e); // If this occurs then the issue is most likely related to the // Java version. // Now check for the method on java 1.5 try { deadlocks = (long[]) connection.invoke(new ObjectName("java.lang:type=Threading"), "findMonitorDeadlockedThreads", null, null); } catch (MalformedObjectNameException me) { throw new MetricInvalidException("Error querying for deadlock thread mbean: " + me.getMessage(), me); } catch (JMException ex) { LOGGER.debug("Unable to retrieve DeadlockedThreads count: ", ex); throw new MetricUnreachableException( "Unable to reach deadlock thread mbean: " + ex.getMessage(), ex); } } if (deadlocks != null) { deadlockCount = deadlocks.length; } return deadlockCount; } catch (IOException e) { throw new MetricUnreachableException("Error querying for deadlock thread mbean: " + e.getMessage(), e); } } // Commented out for TCS-71 // private GarbageCollectorMXBean getGarbageCollectorMXBean( // MBeanServerConnection connection, ObjectName garbageCollector) // throws IOException { // return ManagementFactory.newPlatformMXBeanProxy(connection, // garbageCollector.toString(), GarbageCollectorMXBean.class); // // } private long getJvmUptime(MBeanServerConnection connection) throws MetricUnreachableException { String upTimeQuery = "java.lang:type=Runtime"; RuntimeMXBean bean; try { bean = getRuntimeMXBean(connection, upTimeQuery); } catch (IOException e) { throw new MetricUnreachableException("Error obtaining process UpTime:" + e.getMessage(), e); } return bean.getUptime(); } private RuntimeMXBean getRuntimeMXBean(MBeanServerConnection connection, String upTimeQuery) throws IOException { return ManagementFactory.newPlatformMXBeanProxy(connection, upTimeQuery, RuntimeMXBean.class); } private long getTotalGarbageCollectionTime(MBeanServerConnection connection) throws MetricUnreachableException, MetricNotFoundException, PluginException { long totalGcTimeMillis = 0; try { // Use of the MXBean replaced by plain old JMX query for TCS-71 // // Set<ObjectName> garbageCollectors = connection.queryNames( // new ObjectName("java.lang:type=GarbageCollector,*"), null); // for (ObjectName garbageCollectorName : garbageCollectors) { // GarbageCollectorMXBean garbageCollector = getGarbageCollectorMXBean( // connection, garbageCollectorName); // long collectionTime = garbageCollector.getCollectionTime(); ObjectName gcObjName = new ObjectName("java.lang:type=GarbageCollector,*"); Set<ObjectInstance> garbageCollectors = connection.queryMBeans(gcObjName, null); for (ObjectInstance instance : garbageCollectors) { ObjectName instanceName = instance.getObjectName(); Long l = (Long) connection.getAttribute(instance.getObjectName(), "CollectionTime"); long collectionTime = l.longValue(); LOGGER.debug(instanceName + "::CollectionTime=" + collectionTime); if (collectionTime > -1) { totalGcTimeMillis += collectionTime; } } } catch (MalformedObjectNameException e) { throw new MetricInvalidException("Error querying for GarbageCollector MBeans: " + e.getMessage(), e); } catch (IOException e) { throw new MetricUnreachableException("Error querying for GarbageCollector MBeans:" + e.getMessage(), e); } catch (AttributeNotFoundException e) { throw new MetricNotFoundException("Error querying for GarbageCollector MBeans:" + e.getMessage(), e); } catch (InstanceNotFoundException e) { throw new MetricNotFoundException("Error querying for GarbageCollector MBeans:" + e.getMessage(), e); } catch (MBeanException e) { throw new PluginException("Error querying for GarbageCollector MBeans:" + e.getMessage(), e); } catch (ReflectionException e) { throw new PluginException("Error querying for GarbageCollector MBeans:" + e.getMessage(), e); } catch (NullPointerException e) { throw new PluginException("Error querying for GarbageCollector MBeans:" + e.getMessage(), e); } return totalGcTimeMillis; } private long getFreeHeapMemory(MBeanServerConnection connection) throws MetricUnreachableException { try { MemoryMXBean memoryBean = ManagementFactory.newPlatformMXBeanProxy(connection, "java.lang:type=Memory", MemoryMXBean.class); long max = memoryBean.getHeapMemoryUsage().getMax(); long used = memoryBean.getHeapMemoryUsage().getUsed(); return max - used; } catch (IOException e) { throw new MetricUnreachableException("Error retrieving Memory MBean" + e.getMessage(), e); } } private MetricValue getPercentActiveConnections(MBeanServerConnection connection, Metric metric) throws MetricUnreachableException, MetricNotFoundException, PluginException { int numActiveConnections = 0; int maxActiveConnections = 0; try { ObjectName dataSourceObjectName = new ObjectName(metric.getObjectName()); numActiveConnections = ((Integer) connection.getAttribute(dataSourceObjectName, "numActive")) .intValue(); maxActiveConnections = ((Integer) connection.getAttribute(dataSourceObjectName, "maxActive")) .intValue(); } catch (MalformedObjectNameException e) { throw new MetricInvalidException("Error querying for DataSource MBeans: " + e.getMessage(), e); } catch (IOException e) { throw new MetricUnreachableException("Error querying for DataSource MBeans:" + e.getMessage(), e); } catch (AttributeNotFoundException e) { throw new MetricNotFoundException("Error querying for DataSource MBeans:" + e.getMessage(), e); } catch (InstanceNotFoundException e) { throw new MetricNotFoundException("Error querying for DataSource MBeans:" + e.getMessage(), e); } catch (MBeanException e) { throw new PluginException("Error querying for DataSource MBeans:" + e.getMessage(), e); } catch (ReflectionException e) { throw new PluginException("Error querying for DataSource MBeans:" + e.getMessage(), e); } catch (NullPointerException e) { throw new PluginException("Error querying for DataSource MBeans:" + e.getMessage(), e); } return new MetricValue(100d * (double) numActiveConnections / (double) maxActiveConnections); } private MetricValue getPercentAllocatedThreads(MBeanServerConnection connection, Metric metric) throws MetricUnreachableException, MetricNotFoundException, PluginException { int currentThreadCount = 0; int maxThreads = 0; try { ObjectName threadPoolObjectName = new ObjectName(metric.getObjectName()); currentThreadCount = ((Integer) connection.getAttribute(threadPoolObjectName, "currentThreadCount")) .intValue(); maxThreads = ((Integer) connection.getAttribute(threadPoolObjectName, "maxThreads")).intValue(); } catch (MalformedObjectNameException e) { throw new MetricInvalidException("Error querying for Thread Pool MBeans: " + e.getMessage(), e); } catch (IOException e) { throw new MetricUnreachableException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } catch (AttributeNotFoundException e) { throw new MetricNotFoundException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } catch (InstanceNotFoundException e) { throw new MetricNotFoundException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } catch (MBeanException e) { throw new PluginException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } catch (ReflectionException e) { throw new PluginException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } catch (NullPointerException e) { throw new PluginException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } return new MetricValue(100d * (double) currentThreadCount / (double) maxThreads); } private MetricValue getPercentActiveThreads(MBeanServerConnection connection, Metric metric) throws MetricUnreachableException, MetricNotFoundException, PluginException { int currentThreadsBusy = 0; int maxThreads = 0; try { ObjectName threadPoolObjectName = new ObjectName(metric.getObjectName()); currentThreadsBusy = ((Integer) connection.getAttribute(threadPoolObjectName, "currentThreadsBusy")) .intValue(); maxThreads = ((Integer) connection.getAttribute(threadPoolObjectName, "maxThreads")).intValue(); } catch (MalformedObjectNameException e) { throw new MetricInvalidException("Error querying for Thread Pool MBeans: " + e.getMessage(), e); } catch (IOException e) { throw new MetricUnreachableException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } catch (AttributeNotFoundException e) { throw new MetricNotFoundException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } catch (InstanceNotFoundException e) { throw new MetricNotFoundException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } catch (MBeanException e) { throw new PluginException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } catch (ReflectionException e) { throw new PluginException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } catch (NullPointerException e) { throw new PluginException("Error querying for Thread Pool MBeans:" + e.getMessage(), e); } return new MetricValue(100d * (double) currentThreadsBusy / (double) maxThreads); } @Override public MetricValue getValue(Metric metric) throws PluginException, MetricNotFoundException, MetricUnreachableException { if (PERCENT_UP_TIME_IN_GARBAGE_COLLECTION_METRIC_NAME.equals(metric.getAttributeName())) { return new MetricValue(percentUptimeInGarbageCollection(getConnection(metric.getProperties()))); } else if (DEADLOCKED_DETECTION_COUNT.equals(metric.getAttributeName())) { return new MetricValue(getDeadlockedThreadCount(getConnection(metric.getProperties()))); } else if (HEAP_FREE_MEMORY.equals(metric.getAttributeName())) { return new MetricValue(getFreeHeapMemory(getConnection(metric.getProperties()))); } else if (PERCENT_ACTIVE_CONNECTIONS.equals(metric.getAttributeName())) { return new MetricValue(getPercentActiveConnections(getConnection(metric.getProperties()), metric)); } else if (PERCENT_ALLOCATED_THREADS.equals(metric.getAttributeName())) { return new MetricValue(getPercentAllocatedThreads(getConnection(metric.getProperties()), metric)); } else if (PERCENT_ACTIVE_THREADS.equals(metric.getAttributeName())) { return new MetricValue(getPercentActiveThreads(getConnection(metric.getProperties()), metric)); } return super.getValue(metric); } }