Mercurial > hg > release > thermostat-0.7
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; + } + +}