/* * Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved * http://www.griddynamics.com * * This library is free software; you can redistribute it and/or modify it under the terms of * the Apache License; either * version 2.0 of the License, or any later version. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.griddynamics.jagger.agent.impl; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.griddynamics.jagger.agent.model.*; import com.griddynamics.jagger.dbapi.parameter.DefaultMonitoringParameters; import com.griddynamics.jagger.util.ConfigurableExecutor; import com.sun.management.UnixOperatingSystemMXBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Required; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import java.io.IOException; import java.lang.management.*; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.Future; import static com.griddynamics.jagger.util.Units.bytesToMiB; /** * User: vshulga * Date: 7/5/11 * Time: 4:45 PM * <p/> * JMX implementation of service for retrieving information about GC. * Could be used for multiple systems monitoring on the same host (portsForMonitoring). */ public class JMXSystemUnderTestImpl implements SystemUnderTestService { private final static Logger log = LoggerFactory.getLogger(JMXSystemUnderTestImpl.class); private static final Collection<String> OLD_GEN_GC = ImmutableSet.of("MarkSweepCompact", "PS MarkSweep", "ConcurrentMarkSweep", "G1 Old Generation"); private AgentContext context; private String name; private Map<String, MBeanServerConnection> connections = Maps.newHashMap(); private ConfigurableExecutor executor; private JmxConnector jmxConnector; private Future<Map<String, MBeanServerConnection>> future; public String getName() { return name; } public void setName(String name) { this.name = name; } @Required public void setExecutor(ConfigurableExecutor executor) { this.executor = executor; } @Required public void setJmxConnector(JmxConnector jmxConnector) { this.jmxConnector = jmxConnector; } @Override public Map<String, SystemUnderTestInfo> getInfo() { if (connections.size() == 0) { connections = getEstablishedJmxConnections(); } if (connections.size() > 0) { Map<String, SystemUnderTestInfo> result = Maps.newHashMap(); for (String identifier : connections.keySet()) { result.put(identifier, analyzeJVM(identifier)); } return result; } else { log.warn("JMX connection is not initialized. Skip"); return null; } } @Override public Map<String, Map<String,String>> getSystemProperties() { if (connections.size() == 0) { connections = getEstablishedJmxConnections(); } if (connections.size() > 0) { Map<String, Map<String,String>> result = Maps.newHashMap(); try { for (String identifier : connections.keySet()){ MBeanServerConnection connection = connections.get(identifier); RuntimeMXBean runtimeMXBean = ManagementFactory.newPlatformMXBeanProxy(connection, ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class); result.put(identifier, runtimeMXBean.getSystemProperties()); } }catch (IOException ex){ log.error("Error in JMXSigarMonitorController.analyzeJVM", ex); } return result; } else { log.warn("JMX connection is not initialized. Skip"); return null; } } @Override public void setContext(AgentContext context) { this.context = context; } public void init() { future = executor.submit(new Callable<Map<String, MBeanServerConnection>>() { @Override public Map<String, MBeanServerConnection> call() throws Exception { return jmxConnector.connect(name); } }); } private Map<String, MBeanServerConnection> getEstablishedJmxConnections() { Map<String, MBeanServerConnection> result; if ((future == null) || (!future.isDone())) { return Collections.emptyMap(); } try { result = future.get(); } catch (Exception ex) { // connection failed future = null; log.error("Failed to establish JMX connection"); return Collections.emptyMap(); } return result; } private SystemUnderTestInfo analyzeJVM(String identifier) { SystemUnderTestInfo result = new SystemUnderTestInfo(identifier); long minor_time = 0; long major_time = 0; long minor_units = 0; long major_units = 0; try { MBeanServerConnection connection = connections.get(identifier); // File descriptors try { UnixOperatingSystemMXBean unixOperatingSystemMXBean = ManagementFactory.newPlatformMXBeanProxy(connection, ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, UnixOperatingSystemMXBean.class); result.putSysUTEntry(DefaultMonitoringParameters.OPEN_FILE_DESCRIPTOR_COUNT, (double) unixOperatingSystemMXBean.getOpenFileDescriptorCount()); } catch (Exception e) { log.warn("Can not get count of open file descriptors from '{}' ", identifier, e); } // Heap MemoryMXBean memoryMXBean = ManagementFactory.newPlatformMXBeanProxy(connection, ManagementFactory.MEMORY_MXBEAN_NAME, MemoryMXBean.class); MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage(); result.putSysUTEntry(DefaultMonitoringParameters.HEAP_MEMORY_MAX, bytesToMiB(heapMemoryUsage.getMax())); result.putSysUTEntry(DefaultMonitoringParameters.HEAP_MEMORY_COMMITTED, bytesToMiB(heapMemoryUsage.getCommitted())); result.putSysUTEntry(DefaultMonitoringParameters.HEAP_MEMORY_USED, bytesToMiB(heapMemoryUsage.getUsed())); result.putSysUTEntry(DefaultMonitoringParameters.HEAP_MEMORY_INIT, bytesToMiB(heapMemoryUsage.getInit())); MemoryUsage nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage(); result.putSysUTEntry(DefaultMonitoringParameters.NON_HEAP_MEMORY_MAX, bytesToMiB(nonHeapMemoryUsage.getMax())); result.putSysUTEntry(DefaultMonitoringParameters.NON_HEAP_MEMORY_COMMITTED, bytesToMiB(nonHeapMemoryUsage.getCommitted())); result.putSysUTEntry(DefaultMonitoringParameters.NON_HEAP_MEMORY_USED, bytesToMiB(nonHeapMemoryUsage.getUsed())); result.putSysUTEntry(DefaultMonitoringParameters.NON_HEAP_MEMORY_INIT, bytesToMiB(nonHeapMemoryUsage.getInit())); // Garbage collection Set<ObjectName> srvMemMgrNames = connection.queryNames( new ObjectName(ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*"), null); for (ObjectName gcMgr : srvMemMgrNames) { try { GarbageCollectorMXBean gcMgrBean = ManagementFactory.newPlatformMXBeanProxy(connection, gcMgr.toString(), GarbageCollectorMXBean.class); if (gcMgrBean.isValid()) { boolean majorCollector = OLD_GEN_GC.contains(gcMgrBean.getName()); if (majorCollector) { major_units += gcMgrBean.getCollectionCount(); major_time += gcMgrBean.getCollectionTime(); } else { minor_units += gcMgrBean.getCollectionCount(); minor_time += gcMgrBean.getCollectionTime(); } } } catch (IOException e) { log.error("Error in JMXSigarMonitorController.analyzeJVM", e); } } result.putSysUTEntry(DefaultMonitoringParameters.JMX_GC_MAJOR_TIME, (double) major_time); result.putSysUTEntry(DefaultMonitoringParameters.JMX_GC_MAJOR_UNIT, (double) major_units); result.putSysUTEntry(DefaultMonitoringParameters.JMX_GC_MINOR_TIME, (double) minor_time); result.putSysUTEntry(DefaultMonitoringParameters.JMX_GC_MINOR_UNIT, (double) minor_units); // Threads ThreadMXBean threadMXBean = ManagementFactory.newPlatformMXBeanProxy(connection, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class); result.putSysUTEntry(DefaultMonitoringParameters.THREAD_COUNT, (double) threadMXBean.getThreadCount()); result.putSysUTEntry(DefaultMonitoringParameters.THREAD_PEAK_COUNT, (double) threadMXBean.getPeakThreadCount()); // Custom if (context != null) { List<JmxMetric> jmxMetricList = (List<JmxMetric>) context.getProperty(AgentContext.AgentContextProperty.JMX_METRICS); if (jmxMetricList != null) { for (JmxMetric metric : jmxMetricList) { try { Object num = connection.getAttribute(metric.getObjectName(), metric.getAttributeName()); if (num instanceof Number) { result.putSysUTEntry(metric.getParameter(), ((Number) num).doubleValue()); } else { log.warn("Return value from MBean: '{}'; attribute: '{}'; is not a Number", metric.getObjectName(), metric.getAttributeName()); } } catch (Exception e) { log.error("Can not get from MBean: '{}'; attribute: '{}'", new Object[] {metric.getObjectName(), metric.getAttributeName(), e}); } } } } } catch (Exception ee) { log.error("Error in JMXSigarMonitorController.analyzeJVM", ee); } return result; } }