changeset 17:29ae24fc783d

Use jvmstat to extract basic jvm information
author Omair Majid <omajid@redhat.com>
date Thu, 08 Dec 2011 12:50:52 -0500
parents 75015189e1e8
children 568cabac9d09
files src/com/redhat/thermostat/backend/system/JvmStatDataExtractor.java src/com/redhat/thermostat/backend/system/JvmStatHostListener.java src/com/redhat/thermostat/backend/system/JvmStatVmListener.java src/com/redhat/thermostat/backend/system/SystemBackend.java src/com/redhat/thermostat/common/VmGcStat.java src/com/redhat/thermostat/common/VmInfo.java src/com/redhat/thermostat/common/VmMemoryStat.java
diffstat 7 files changed, 559 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/redhat/thermostat/backend/system/JvmStatDataExtractor.java	Thu Dec 08 12:50:52 2011 -0500
@@ -0,0 +1,115 @@
+package com.redhat.thermostat.backend.system;
+
+import sun.jvmstat.monitor.Monitor;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.MonitoredVmUtil;
+
+/**
+ * A helper class to provide type-safe access to commonly used jvmstat monitors
+ */
+public class JvmStatDataExtractor {
+
+    /*
+     * Note, there may be a performance issue to consider here. We have a lot of
+     * string constants. When we start adding some of the more heavyweight
+     * features, and running into CPU issues this may need to be reconsidered in
+     * order to avoid the String pool overhead. See also:
+     * http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern()
+     */
+
+    private final MonitoredVm vm;
+
+    public JvmStatDataExtractor(MonitoredVm vm) {
+        this.vm = vm;
+    }
+
+    public String getCommandLine() throws MonitorException {
+        return MonitoredVmUtil.commandLine(vm);
+    }
+
+    public String getJavaVersion() throws MonitorException {
+        return (String) vm.findByName("java.property.java.version").getValue();
+    }
+
+    public String getJavaHome() throws MonitorException {
+        return (String) vm.findByName("java.property.java.home").getValue();
+    }
+
+    public String getVmName() throws MonitorException {
+        return (String) vm.findByName("java.property.java.vm.name").getValue();
+    }
+
+    public String getVmInfo() throws MonitorException {
+        return (String) vm.findByName("java.property.java.vm.info").getValue();
+    }
+
+    public String getVmVersion() throws MonitorException {
+        return (String) vm.findByName("java.property.java.vm.version").getValue();
+    }
+
+    public String getVmArguments() throws MonitorException {
+        return MonitoredVmUtil.jvmArgs(vm);
+    }
+
+    public long getTotalCollectors() throws MonitorException {
+        return (Long) vm.findByName("sun.gc.policy.collectors").getValue();
+    }
+
+    public String getCollectorName(long collector) throws MonitorException {
+        return (String) vm.findByName("sun.gc.collector." + collector + ".name").getValue();
+    }
+
+    public long getCollectorTime(long collector) throws MonitorException {
+        return (Long) vm.findByName("sun.gc.collector." + collector + ".time").getValue();
+    }
+
+    public long getCollectorInvocations(long collector) throws MonitorException {
+        return (Long) vm.findByName("sun.gc.collector." + collector + ".invocations").getValue();
+    }
+
+    public long getTotalGcGenerations() throws MonitorException {
+        return (Long) vm.findByName("sun.gc.policy.generations").getValue();
+    }
+
+    public String getGenerationName(long generation) throws MonitorException {
+        return (String) vm.findByName("sun.gc.generation." + generation + ".name").getValue();
+    }
+
+    public long getGenerationCapacity(long generation) throws MonitorException {
+        return (Long) vm.findByName("sun.gc.generation." + generation + ".capacity").getValue();
+    }
+
+    public long getGenerationMaxCapacity(long generation) throws MonitorException {
+        return (Long) vm.findByName("sun.gc.generation." + generation + ".maxCapacity").getValue();
+    }
+
+    public String getGenerationCollector(long generation) throws MonitorException {
+        Monitor m = vm.findByName("sun.gc.collector." + generation + ".name");
+        if (m == null) {
+            throw new IllegalArgumentException("not found");
+        }
+        return (String) m.getValue();
+    }
+
+    public long getTotalSpaces(long generation) throws MonitorException {
+        return (Long) vm.findByName("sun.gc.generation." + generation + ".spaces").getValue();
+    }
+
+    public String getSpaceName(long generation, long space) throws MonitorException {
+        return (String) vm.findByName("sun.gc.generation." + generation + ".space." + space + ".name").getValue();
+    }
+
+    public long getSpaceCapacity(long generation, long space) throws MonitorException {
+        return (Long) vm.findByName("sun.gc.generation." + generation + ".space." + space + ".capacity").getValue();
+    }
+
+    public long getSpaceMaxCapacity(long generation, long space) throws MonitorException {
+        return (Long) vm.findByName("sun.gc.generation." + generation + ".space." + space + ".maxCapacity").getValue();
+    }
+
+    public long getSpaceUsed(long generation, long space) throws MonitorException {
+        return (Long) vm.findByName("sun.gc.generation." + generation + ".space." + space + ".used").getValue();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Thu Dec 08 12:50:52 2011 -0500
@@ -0,0 +1,124 @@
+package com.redhat.thermostat.backend.system;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredHost;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.VmIdentifier;
+import sun.jvmstat.monitor.event.HostEvent;
+import sun.jvmstat.monitor.event.HostListener;
+import sun.jvmstat.monitor.event.VmStatusChangeEvent;
+
+import com.redhat.thermostat.agent.storage.Storage;
+import com.redhat.thermostat.common.VmInfo;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+public class JvmStatHostListener implements HostListener {
+
+    private static final Logger logger = LoggingUtils.getLogger(JvmStatHostListener.class);
+
+    private Storage storage;
+
+    private Map<Integer, JvmStatVmListener> listenerMap = new HashMap<Integer, JvmStatVmListener>();
+
+    public void setStorage(Storage storage) {
+        if (storage == null) {
+            throw new NullPointerException();
+        }
+        this.storage = storage;
+    }
+
+    @Override
+    public void disconnected(HostEvent event) {
+        logger.warning("Disconnected from host");
+    }
+
+    @Override
+    public void vmStatusChanged(VmStatusChangeEvent event) {
+        if (storage == null) {
+            throw new NullPointerException("null");
+        }
+        long currentTime = System.currentTimeMillis();
+
+        MonitoredHost host = event.getMonitoredHost();
+
+        Iterator<Integer> newActive = event.getStarted().iterator();
+        while (newActive.hasNext()) {
+            Integer newVm = newActive.next();
+            try {
+                logger.fine("New vm: " + newVm);
+                sendNewVM(currentTime, newVm, host);
+            } catch (MonitorException e) {
+                logger.log(Level.WARNING, "error getting info for new vm" + newVm, e);
+            } catch (URISyntaxException e) {
+                logger.log(Level.WARNING, "error getting info for new vm" + newVm, e);
+            }
+        }
+
+        Iterator<Integer> newStopped = event.getTerminated().iterator();
+        while (newStopped.hasNext()) {
+            Integer stoppedVm = newStopped.next();
+            try {
+                logger.fine("stopped vm: " + stoppedVm);
+                sendStoppedVM(currentTime, stoppedVm, host);
+            } catch (URISyntaxException e) {
+                logger.log(Level.WARNING, "error getting info for stopped vm" + stoppedVm, e);
+            } catch (MonitorException e) {
+                logger.log(Level.WARNING, "error getting info for new vm" + stoppedVm, e);
+            }
+        }
+    }
+
+    private void sendNewVM(long timestamp, Integer vmId, MonitoredHost host)
+            throws MonitorException, URISyntaxException {
+        MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(
+                new VmIdentifier(vmId.toString())));
+        if (vm != null) {
+
+            VmInfo info = null;
+            try {
+                long stopTime = Long.MIN_VALUE;
+                JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+                Map<String, String> properties = new HashMap<String, String>();
+                Map<String, String> environment = new HashMap<String, String>();
+                List<String> loadedNativeLibraries = new ArrayList<String>();
+                info = new VmInfo(vmId, timestamp, stopTime,
+                        extractor.getJavaVersion(), extractor.getJavaHome(), extractor.getCommandLine(),
+                        extractor.getVmName(), extractor.getVmInfo(), extractor.getVmVersion(), extractor.getVmArguments(),
+                        properties, environment, loadedNativeLibraries);
+                // FIXME storage.addVmInfo(info);
+                logger.finer("Sent VM_STARTED messsage");
+            } catch (MonitorException me) {
+                logger.log(Level.WARNING, "error getting vm info for " + vmId, me);
+            }
+
+            JvmStatVmListener listener = new JvmStatVmListener(storage, vmId);
+            listenerMap.put(vmId, listener);
+            vm.addVmListener(listener);
+        }
+    }
+
+    private void sendStoppedVM(long timestamp, Integer vmId, MonitoredHost host)
+            throws URISyntaxException, MonitorException {
+        VmIdentifier resolvedVmID = host.getHostIdentifier().resolve(
+                new VmIdentifier(vmId.toString()));
+        if (resolvedVmID != null) {
+            MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(
+                    new VmIdentifier(vmId.toString())));
+            if (vm != null) {
+                JvmStatVmListener listener = listenerMap.remove(vmId);
+                vm.removeVmListener(listener);
+            }
+            // TODO record vm as stopped
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/redhat/thermostat/backend/system/JvmStatVmListener.java	Thu Dec 08 12:50:52 2011 -0500
@@ -0,0 +1,109 @@
+package com.redhat.thermostat.backend.system;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.event.MonitorStatusChangeEvent;
+import sun.jvmstat.monitor.event.VmEvent;
+import sun.jvmstat.monitor.event.VmListener;
+
+import com.redhat.thermostat.agent.storage.Storage;
+import com.redhat.thermostat.common.VmGcStat;
+import com.redhat.thermostat.common.VmMemoryStat;
+import com.redhat.thermostat.common.VmMemoryStat.Generation;
+import com.redhat.thermostat.common.VmMemoryStat.Space;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+public class JvmStatVmListener implements VmListener {
+
+    private static final Logger logger = LoggingUtils.getLogger(JvmStatVmListener.class);
+
+    private final int vmId;
+    private final Storage storage;
+
+    public JvmStatVmListener(Storage storage, int vmId) {
+        this.storage = storage;
+        this.vmId = vmId;
+    }
+
+    @Override
+    public void disconnected(VmEvent event) {
+        /* nothing to do here */
+    }
+
+    @Override
+    public void monitorStatusChanged(MonitorStatusChangeEvent event) {
+        /* nothing to do here */
+    }
+
+    @Override
+    public void monitorsUpdated(VmEvent event) {
+        MonitoredVm vm = event.getMonitoredVm();
+        if (vm == null) {
+            throw new NullPointerException();
+        }
+        recordMemoryStat(vm);
+        recordGcStat(vm);
+    }
+
+    private void recordGcStat(MonitoredVm vm) {
+        try {
+            long timestamp = System.currentTimeMillis();
+            JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+            long collectors = extractor.getTotalCollectors();
+            for (int i = 0; i < collectors; i++) {
+                VmGcStat stat = new VmGcStat(vmId, timestamp,
+                        extractor.getCollectorName(i),
+                        extractor.getCollectorInvocations(i),
+                        extractor.getCollectorTime(i));
+                // FIXME storage.addVmGcStat(stat);
+            }
+        } catch (MonitorException e) {
+            logger.log(Level.WARNING, "error gathering gc info for vm " + vmId, e);
+        }
+
+    }
+
+    private void recordMemoryStat(MonitoredVm vm) {
+        try {
+            long timestamp = System.currentTimeMillis();
+            JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
+            long maxGenerations = extractor.getTotalGcGenerations();
+            List<Generation> generations = new ArrayList<Generation>();
+            VmMemoryStat stat = new VmMemoryStat(timestamp, vmId, generations);
+            for (long generation = 0; generation < maxGenerations; generation++) {
+                Generation g = new Generation();
+                generations.add(g);
+                g.name = extractor.getGenerationName(generation);
+                g.capacity = extractor.getGenerationCapacity(generation);
+                g.maxCapacity = extractor.getGenerationMaxCapacity(generation);
+                try {
+                    g.collector = extractor.getGenerationCollector(generation);
+                } catch (IllegalArgumentException iae) {
+                    /* no collector for this generation */
+                    g.collector = Generation.COLLECTOR_NONE;
+                }
+                long maxSpaces = extractor.getTotalSpaces(generation);
+                List<Space> spaces = new ArrayList<Space>();
+                g.spaces = spaces;
+                for (long space = 0; space < maxSpaces; space++) {
+                    Space s = new Space();
+                    spaces.add(s);
+                    s.index = (int) space;
+                    s.name = extractor.getSpaceName(generation, space);
+                    s.capacity = extractor.getSpaceCapacity(generation, space);
+                    s.maxCapacity = extractor.getSpaceMaxCapacity(generation, space);
+                    s.used = extractor.getSpaceUsed(generation, space);
+                }
+            }
+            // FIXME storage.addVmMemoryStat(stat);
+        } catch (MonitorException e) {
+            logger.log(Level.WARNING, "error gathering memory info for vm " + vmId, e);
+        }
+    }
+
+}
--- a/src/com/redhat/thermostat/backend/system/SystemBackend.java	Wed Dec 07 17:41:30 2011 -0500
+++ b/src/com/redhat/thermostat/backend/system/SystemBackend.java	Thu Dec 08 12:50:52 2011 -0500
@@ -1,11 +1,16 @@
 package com.redhat.thermostat.backend.system;
 
+import java.net.URISyntaxException;
 import java.util.Map;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import sun.jvmstat.monitor.HostIdentifier;
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredHost;
+
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.common.CpuStat;
 import com.redhat.thermostat.common.HostInfo;
@@ -26,6 +31,11 @@
 
     private Timer timer = null;
 
+    private HostIdentifier hostId = null;
+    private MonitoredHost host = null;
+    private JvmStatHostListener hostListener = new JvmStatHostListener();
+
+
     @Override
     protected void setConfigurationValue(String name, String value) {
         logger.log(Level.INFO, "configuring " + NAME + " not supported");
@@ -77,6 +87,17 @@
             }
         }, 0, procCheckInterval);
 
+        try {
+            hostId = new HostIdentifier((String) null);
+            host = MonitoredHost.getMonitoredHost(hostId);
+            hostListener.setStorage(storage);
+            host.addHostListener(hostListener);
+        } catch (MonitorException me) {
+            logger.log(Level.WARNING , "problems with connecting jvmstat to local machien" , me);
+        } catch (URISyntaxException use) {
+            logger.log(Level.WARNING , "problems with connecting jvmstat to local machien" , use);
+        }
+
         return true;
     }
 
@@ -89,6 +110,14 @@
         timer.cancel();
         timer = null;
 
+        try {
+            host.removeHostListener(hostListener);
+        } catch (MonitorException me) {
+            logger.log(Level.INFO, "something went wront in jvmstat's listeningto this host");
+        }
+        host = null;
+        hostId = null;
+
         return true;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/redhat/thermostat/common/VmGcStat.java	Thu Dec 08 12:50:52 2011 -0500
@@ -0,0 +1,34 @@
+package com.redhat.thermostat.common;
+
+public class VmGcStat {
+
+    private final long timestamp;
+    private final int vmId;
+    private final String collectorName;
+    private final long runCount;
+    private final long wallTime;
+
+    public VmGcStat(int vmId, long timestamp, String collectorName, long runCount, long wallTime) {
+        this.timestamp = timestamp;
+        this.vmId = vmId;
+        this.collectorName = collectorName;
+        this.runCount = runCount;
+        this.wallTime = wallTime;
+    }
+    public int getVmId() {
+        return vmId;
+    }
+    public String getCollectorName() {
+        return collectorName;
+    }
+    public long getRunCount() {
+        return runCount;
+    }
+    public long getWallTime() {
+        return wallTime;
+    }
+
+    public long getTimeStamp() {
+        return timestamp;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/redhat/thermostat/common/VmInfo.java	Thu Dec 08 12:50:52 2011 -0500
@@ -0,0 +1,102 @@
+package com.redhat.thermostat.common;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class VmInfo {
+
+    private int vmPid = 0;
+    private long startTime = System.currentTimeMillis();
+    private long stopTime = Long.MIN_VALUE;
+    private String javaVersion = "unknown";
+    private String javaHome = "unknown";
+    private String javaCommandLine = "unknown";
+    private String vmName = "unknown";
+    private String vmInfo = "unknown";
+    private String vmVersion = "unknown";
+    private String vmArguments = "unknown";
+    private Map<String, String> properties = new HashMap<String, String>();
+    private Map<String, String> environment = new HashMap<String, String>();
+    private List<String> loadedNativeLibraries;
+
+    public VmInfo() {
+        /* use defaults */
+    }
+
+    public VmInfo(int vmPid, long startTime, long stopTime,
+            String javaVersion, String javaHome, String commandLine,
+            String vmName, String vmInfo, String vmVersion, String vmArguments,
+            Map<String, String> properties, Map<String, String> environment, List<String> loadedNativeLibraries) {
+        this.vmPid = vmPid;
+        this.startTime = startTime;
+        this.stopTime = stopTime;
+        this.javaVersion = javaVersion;
+        this.javaHome = javaHome;
+        this.javaCommandLine = commandLine;
+        this.vmName = vmName;
+        this.vmInfo = vmInfo;
+        this.vmVersion = vmVersion;
+        this.vmArguments = vmArguments;
+        this.properties = properties;
+        this.environment = environment;
+        this.loadedNativeLibraries = loadedNativeLibraries;
+    }
+
+    public int getVmId() {
+        return vmPid;
+    }
+
+    public int getVmPid() {
+        return vmPid;
+    }
+
+    public long getStartTimeStamp() {
+        return startTime;
+    }
+
+    public long getStopTimeStamp() {
+        return stopTime;
+    }
+
+    public String getJavaVersion() {
+        return javaVersion;
+    }
+
+    public String getJavaHome() {
+        return javaHome;
+    }
+
+    public String getJavaCommandLine() {
+        return javaCommandLine;
+    }
+
+    public String getVmName() {
+        return vmName;
+    }
+
+    public String getVmArguments() {
+        return vmArguments;
+    }
+
+    public String getVmInfo() {
+        return vmInfo;
+    }
+
+    public String getVmVersion() {
+        return vmVersion;
+    }
+
+    public Map<String, String> getProperties() {
+        return properties;
+    }
+
+    public Map<String, String> getEnvironment() {
+        return environment;
+    }
+
+    public List<String> getLoadedNativeLibraries() {
+        return loadedNativeLibraries;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/redhat/thermostat/common/VmMemoryStat.java	Thu Dec 08 12:50:52 2011 -0500
@@ -0,0 +1,46 @@
+package com.redhat.thermostat.common;
+
+import java.util.List;
+
+public class VmMemoryStat {
+
+    public static class Generation {
+        public static final String COLLECTOR_NONE = "none";
+        public String name;
+        public long capacity;
+        public long maxCapacity;
+        public List<Space> spaces;
+        public String collector;
+    }
+
+    public static class Space {
+        public int index;
+        public String name;
+        public long capacity;
+        public long maxCapacity;
+        public long used;
+    }
+
+    private final List<Generation> generations;
+    private final long timestamp;
+    private final int vmId;
+
+    public VmMemoryStat(long timestamp, int vmId, List<Generation> generations) {
+        this.timestamp = timestamp;
+        this.vmId = vmId;
+        this.generations = generations;
+    }
+
+    public int getVmId() {
+        return vmId;
+    }
+
+    public long getTimeStamp() {
+        return timestamp;
+    }
+
+    public List<Generation> getGenerations() {
+        return generations;
+    }
+
+}