diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..59f307b --- /dev/null +++ b/.gitignore @@ -0,0 +1,143 @@ + +# Created by https://www.gitignore.io/api/maven +# Edit at https://www.gitignore.io/?templates=maven + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + +# End of https://www.gitignore.io/api/maven + + +# Created by https://www.gitignore.io/api/java +# Edit at https://www.gitignore.io/?templates=java + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +# End of https://www.gitignore.io/api/java + + + +# Created by https://www.gitignore.io/api/intellij +# Edit at https://www.gitignore.io/?templates=intellij + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +# JetBrains templates +**___jb_tmp___ + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint +.idea +.vscode +.settings +.project +.classpath +*.iml + +# End of https://www.gitignore.io/api/intellij \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..adc69e1 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,24 @@ +Copyright (c) 2019, BMD software +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +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 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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..58d1ab9 --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ + # Resource Monitor for Java (rmjvm) + + ## Description + + Resource Monitor for Java is a tool that helps to monitor Java process resources and detect memory leaks/CPU constrains. + + ## How to use? + + Before you use this tool, you need to be aware what are your goals. First step, is to understand what kind of application that + you need to monitor and what are the moments to monitor and actions that you need to trigger. + +``` +rmjvm 1.0 +usage: rmjvm [-c] [-e ] [-ed ] [-h] [-ho ] [-p ] [-s + ] + -c,--check check will run all the actionsand wait + until it is requested to stop. Meanwhile it + will monitoring the memory and compare + -e,--export export format (csv, output) + -ed,--exportdirectory export directory where will be stored the + files. + -h,--help help shows how to use the rmjvm and what + its core funcionality + -ho,--host set the hostname for JMX of java listen + process + -p,--port set the port for JMX of java listen process + -s,--skip skip the cpu or memory (--skip=mem,cpu) + +``` + +## Examples + +Few examples of use of the application: + + ``` + +$ rmjvm --help +$ rmjvm --version +$ rmjvm --check +$ rmjvm --skip=mem +$ rmjvm --skip=cpu,mem +$ rmjvm --export=csv --exportdirectory=/tmp/dump-reports + +``` + + + ## Recommended tools + + You should be aware at least of two tools: + + - jConsole + - Mission Control and Flight Recorder + - Oracle VisualVM + - JVM tools: https://github.com/aragozin/jvm-tools/ + - Eclipse Memory Analyser: MAT + +## Other resources + + - https://www.sderosiaux.com/articles/2017/02/14/all-the-things-we-can-do-with-jmx/ + - https://sysdig.com/blog/jmx-monitoring-custom-metrics/ + + ## Contribute + + You can contribute for the project by send Pull Requests. + + Build >= JDK12 + +## Support + +It is an open source project and no enterprise support is provided, only by the community. + +[BMD Software](https://www.bmd-software.com) + +Please contact [BMD Software](https://www.bmd-software.com) for more information. \ No newline at end of file diff --git a/bin/rmjvm.sh b/bin/rmjvm.sh new file mode 100644 index 0000000..20d602b --- /dev/null +++ b/bin/rmjvm.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash + diff --git a/conf/rmjvm-dicoogle.yml b/conf/rmjvm-dicoogle.yml new file mode 100644 index 0000000..edb3f6e --- /dev/null +++ b/conf/rmjvm-dicoogle.yml @@ -0,0 +1,30 @@ +### This is only an example. +### Please modify according your needs + + +application: + uri: "service:jmx:rmi:///jndi/rmi://localhost:3333/jmxrmi" + directory: "c:/Users/bastiao/Projects/dicoogle/dicoogle/target/" + + +# This is just few examples for monitoring Dicoogle (e.g. https://github.com/BMDSoftware/dicoogle) +# Others examples could also be used. + +actions: + - name: monitor-dicom-store + cmd: "c:\\Users\\bastiao\\Software\\dcm4che-5.16.3-bin\\dcm4che-5.16.3\\bin\\ianscu.bat -c DICOOGLE-STORAGE@localhost:6666" + timeout: 0 # ms + monitor: ['cpu', 'mem'] + executions: 20 + - name: monitor-dicom-qr + cmd: "c:\\Users\\bastiao\\Software\\dcm4che-5.16.3-bin\\dcm4che-5.16.3\\bin\\ianscu.bat -c DICOOGLE-STORAGE@localhost:1045" + monitor: ['mem'] + timeout: 0 # ms + executions: 2 + +# configure a tracer +# there are few examples, such zipkin +tracer: + - uri: "http://my-zipkin-deployment:9201" + + diff --git a/conf/rmjvm.yml b/conf/rmjvm.yml new file mode 100644 index 0000000..6544083 --- /dev/null +++ b/conf/rmjvm.yml @@ -0,0 +1,27 @@ +### This is only an example. +### Please modify according your needs + + +application: + uri: "service:jmx:rmi:///jndi/rmi://:/jmxrmi" + directory: "" + + +# This is just few examples for monitoring + +actions: + - name: monitor01 + cmd: "sendFilesApp -h hostname" + timeout: 200 # ms + monitor: ['cpu', 'mem'] + executions: 20 + - name: monitor02 + cmd: "receiveFilesApp -h hostname" + monitor: ['mem'] + timeout: 100 # ms + executions: 2 + +# configure a tracer +# there are few examples, such zipkin +tracer: + - uri: "http://my-zipkin-deployment:9201" diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..389397a --- /dev/null +++ b/pom.xml @@ -0,0 +1,137 @@ + + + 4.0.0 + + com.bmdsoftware.monitor + rmjvm + 1.0-SNAPSHOT + + + 1.8 + 1.8 + 1.6.1 + + + + + + + maven-surefire-plugin + 2.22.0 + + + maven-failsafe-plugin + 2.22.0 + + + + maven-assembly-plugin + + + + com.bmdsoftware.monitor.resourcemonitor.Main + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + + + + + + + org.slf4j + slf4j-api + ${slf4jVersion} + + + + ch.qos.logback + logback-classic + 1.0.13 + + + + org.buildobjects + jproc + 2.2.3 + + + org.gridkit.jvmtool + hprof-heap + 0.10.1 + + + org.gridkit.jvmtool + hprof-heap + 0.10.1 + + + + + commons-cli + commons-cli + 1.4 + + + + org.yaml + snakeyaml + 1.21 + + + + io.zipkin.brave + brave + 5.6.3 + + + + + io.zipkin.reporter2 + zipkin-reporter + 2.6.0 + + + io.zipkin.reporter2 + zipkin-sender-okhttp3 + 2.6.0 + + + + + org.junit.jupiter + junit-jupiter-api + 5.4.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.4.2 + test + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/Main.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/Main.java new file mode 100644 index 0000000..1492bd6 --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/Main.java @@ -0,0 +1,583 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.management.MonitorInfo; +import java.net.MalformedURLException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.openmbean.CompositeData; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import com.bmdsoftware.monitor.resourcemonitor.actions.Action; +import com.bmdsoftware.monitor.resourcemonitor.conf.YmlConfig; +import com.bmdsoftware.monitor.resourcemonitor.jmx.JMXConnection; +import com.bmdsoftware.monitor.resourcemonitor.memory.MemoryChecker; +import com.bmdsoftware.monitor.resourcemonitor.memory.imp.MemoryCheckImp; +import com.bmdsoftware.monitor.resourcemonitor.utils.Consts; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * The main class for the rmjvm + * + * @author Luís A. Bastião Silva + */ +public class Main { + + private static String PROJECT_NAME = "rmjvm"; + private static String VERSION = "1.0"; + + private static Logger logger = LoggerFactory.getLogger(Main.class); + + private boolean check = false; + private boolean checkMemory = false; + private boolean checkCPU = false; + private boolean export = false; + private String exportDirectory = ""; + private String hostname = ""; + private Integer port; + private Map dumpFiles = new HashMap<>(); + // Yml Configuration. + private YmlConfig config = null; + + + /** + * + * Constructor with major settings + * + * @param check + * @param checkMemory + * @param checkCPU + * @param export + * @param exportDirectory + * @param hostname + * @param port + */ + public Main(boolean check, boolean checkMemory, boolean checkCPU, boolean export, String exportDirectory, String hostname, Integer port) { + this.check = check; + this.checkMemory = checkMemory; + this.checkCPU = checkCPU; + this.export = export; + this.exportDirectory = exportDirectory; + this.hostname = hostname; + this.port = port; + } + + // Default constructor + + public Main() { + + } + + + public static void main(String[] args) { + + logger.info("ResourceMonitor: started"); + + // Default configuration file + String configurationFile = "conf" + File.separator + "rmjvm.yml"; + + // Configure options + Options options = new Options(); + + Option help = new Option("h", "help", false, "help shows how to use the rmjvm and what its core funcionality"); + options.addOption(help); + + Option hostOpt = new Option("ho", "host", false, "set the hostname for JMX of java listen process"); + hostOpt.setArgs(1); + options.addOption(hostOpt); + + Option portOpt = new Option("p", "port", false, "set the port for JMX of java listen process"); + portOpt.setArgs(1); + options.addOption(portOpt); + + + Option checkOpt = new Option("c", "check", false, "check will run all the actions" + + "and wait until it is requested to stop. Meanwhile it will monitoring the memory and compare "); + checkOpt.setArgs(0); + options.addOption(checkOpt); + + Option skipOpt = new Option("s", "skip", false, "skip the cpu or memory (--skip=mem,cpu) "); + skipOpt.setArgs(1); + options.addOption(skipOpt); + + + Option exportOpt = new Option("e", "export", false, "export format (csv, output) "); + exportOpt.setArgs(1); + options.addOption(exportOpt); + + Option exportDirOpt = new Option("ed", "exportdirectory", false, "export directory where will be stored the files."); + exportDirOpt.setArgs(1); + options.addOption(exportDirOpt); + + + // Configure Command Line Parser + CommandLineParser parser = new DefaultParser(); + CommandLine cmd = null; + Main app = new Main(); + + // Load the configuration file. + // If any options is passed by the command line, the command line will overwrite + // the configurations file + try { + YmlConfig config = new YmlConfig(new File(configurationFile)); + config.load(); + app.setConfig(config); + System.out.println("Config: loaded."); + } catch (FileNotFoundException e1) { + logger.error("There is a problem locating configuration file " + configurationFile, e1); + System.err.println("Error: there is a problem locating configuration file" + configurationFile); + System.exit(Consts.ERROR_WHILE_PARSING); + } + + // Parse options from command line. + try { + cmd = parser.parse( options, args); + } catch (ParseException e) { + logger.error("ResourceMonitor: error while parsing the command line options", e); + System.err.println("Error: error while parsing the command line options" + configurationFile); + System.exit(Consts.ERROR_WHILE_PARSING); + } + + // Check the options and call the correct options. + + if (cmd.hasOption("help")) { + HelpFormatter formatter = new HelpFormatter(); + System.out.println(PROJECT_NAME + " " + VERSION); + formatter.printHelp(PROJECT_NAME, options, true); + } else if (cmd.hasOption("version")) { + System.out.println("version: " + VERSION); + } + else if (cmd.hasOption("check")) { + System.out.println("Checking .."); + app.setCheck(true); + } + else if (cmd.hasOption("host")) { + System.out.println("Host: "); + String hostname = cmd.getOptionValue("host"); + app.setHostname(hostname); + } + else if (cmd.hasOption("port")) { + System.out.println("Port: "); + String port = cmd.getOptionValue("port"); + Integer portInt = Integer.parseInt(port); + app.setPort(portInt); + } + else if (cmd.hasOption("skip")) { + // Get what are going skip analysis. + String [] skipOpts = cmd.getOptionValues("skip"); + for (int i = 0; i actions = this.config.getActions(); + + // Execute the actions + if (actions!=null) { + for (Action a : actions) { + logger.debug("Action " + a.toString()); + + for (int i = 0; i0) { + try { + + Thread.sleep(a.getTimeout()); + } catch (InterruptedException e) { + logger.error("Problem while waiting for timeout", e); + } + } + + JMXConnection connection = new JMXConnection(config.getUriJmxService()); + // Monitor + List monitor = a.getMonitor(); + if (monitor.contains("cpu")){ + // TODO: to be implemented. + } + if (monitor.contains("mem")){ + + MemoryChecker check = new MemoryCheckImp(connection,config.getApplicationDirectory()); + try { + check.monitor(); + } catch (IOException e) { + logger.error("Error while monitoring memory ", e); + } + + } + + + } + + } + } + else + { + System.out.println("Warning: no actions available to execute. Please configure it first."); + } + // Execute the actions and dumps the results + + } + /** + * + */ + public void monitorCPU(){ + + } + + /** + * + */ + public void monitorMem(){ + + } + + public void getFinalReport(){ + + } + + public static void getMetrics(){ + + + String hostName = "localhost"; + Integer portNum = 3333; + + JMXServiceURL u = null; + try { + u = new JMXServiceURL( + "service:jmx:rmi:///jndi/rmi://" + hostName + ":" + portNum + "/jmxrmi"); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + try { + JMXConnector c = JMXConnectorFactory.connect(u); + +//create object instances that will be used to get memory and operating system Mbean objects exposed by JMX; create variables for cpu time and system time before + Object memoryMbean = null; + Object osMbean = null; + long cpuBefore = 0; + long tempMemory = 0; + int samplesCount = 10; + CompositeData cd = null; + JMXConnector jmxc = c; + + cpuBefore = 0; + +// call the garbage collector before the test using the Memory Mbean + jmxc.getMBeanServerConnection().invoke(new ObjectName("java.lang:type=Memory"), "gc", null, null); + +//create a loop to get values every second (optional) + for (int i = 0; i < samplesCount; i++) { + +//get an instance of the HeapMemoryUsage Mbean + memoryMbean = jmxc.getMBeanServerConnection().getAttribute(new ObjectName("java.lang:type=Memory"), "HeapMemoryUsage"); + cd = (CompositeData) memoryMbean; +//get an instance of the OperatingSystem Mbean + osMbean = jmxc.getMBeanServerConnection().getAttribute(new ObjectName("java.lang:type=OperatingSystem"),"ProcessCpuTime"); + System.out.println("Used memory: " + " " + cd.get("used") + " Used cpu: " + osMbean); //print memory usage + tempMemory = tempMemory + Long.parseLong(cd.get("used").toString()); + + + memoryMbean = jmxc.getMBeanServerConnection().getAttribute(new ObjectName("java.lang:type=Memory"), "NonHeapMemoryUsage"); + + cd = (CompositeData) memoryMbean; + System.out.println("Used NON HEAP memory: " + " " + cd.get("used") + " Used cpu: " + osMbean); //print memory usage + + + + Thread.sleep(1000); //delay for one second + } + +//get system time and cpu time from last poll + long cpuAfter = Long.parseLong(osMbean.toString()); + + + + long cpuDiff = cpuAfter - cpuBefore; //find cpu time between our first and last jmx poll + System.out.println("Cpu diff in milli seconds: " + cpuDiff / 1000000); //print cpu time in miliseconds + System.out.println("average memory usage is: " + tempMemory / samplesCount);//print average memory usage + + Set objectInstances = c.getMBeanServerConnection().queryMBeans(null, null); + + + objectInstances.stream().forEach(instance -> System.out.println(instance)); + MBeanInfo info = c.getMBeanServerConnection().getMBeanInfo(new ObjectName("java.lang:type=Memory")); + + for (MBeanAttributeInfo element : info.getAttributes()) + { + Object value; + if (element.isReadable()) + { + try + { + value = c.getMBeanServerConnection().getAttribute(new ObjectName("java.lang:type=Memory"), element.getName()); + System.out.println(element.getName()); + System.out.println(value.toString()); + } + catch (Exception e) + { + } + } + else + { + } + } +/* + HotSpotDiagnosticMXBean bean = + ManagementFactory.newPlatformMXBeanProxy(server, + HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean.class); +*/ + + } catch (IOException e) { + e.printStackTrace(); + } catch (ReflectionException e) { + e.printStackTrace(); + } catch (InstanceNotFoundException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (AttributeNotFoundException e) { + e.printStackTrace(); + } catch (MBeanException e) { + e.printStackTrace(); + } catch (MalformedObjectNameException e) { + e.printStackTrace(); + } catch (IntrospectionException e) { + e.printStackTrace(); + } + + + } + + + public Main(boolean check, boolean checkMemory, boolean checkCPU, boolean export, String exportDirectory) { + this.check = check; + this.checkMemory = checkMemory; + this.checkCPU = checkCPU; + this.export = export; + this.exportDirectory = exportDirectory; + } + + public boolean isCheck() { + return this.check; + } + + public boolean getCheck() { + return this.check; + } + + public void setCheck(boolean check) { + this.check = check; + } + + public boolean isCheckMemory() { + return this.checkMemory; + } + + public boolean getCheckMemory() { + return this.checkMemory; + } + + public void setCheckMemory(boolean checkMemory) { + this.checkMemory = checkMemory; + } + + public boolean isCheckCPU() { + return this.checkCPU; + } + + public boolean getCheckCPU() { + return this.checkCPU; + } + + public void setCheckCPU(boolean checkCPU) { + this.checkCPU = checkCPU; + } + + public boolean isExport() { + return this.export; + } + + public boolean getExport() { + return this.export; + } + + public void setExport(boolean export) { + this.export = export; + } + + public String getExportDirectory() { + return this.exportDirectory; + } + + public void setExportDirectory(String exportDirectory) { + this.exportDirectory = exportDirectory; + } + + public Main checkMemory(boolean checkMemory) { + this.checkMemory = checkMemory; + return this; + } + + public Main checkCPU(boolean checkCPU) { + this.checkCPU = checkCPU; + return this; + } + + public Main export(boolean export) { + this.export = export; + return this; + } + + public Main exportDirectory(String exportDirectory) { + this.exportDirectory = exportDirectory; + return this; + } + + + public String getHostname() { + return this.hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public Integer getPort() { + return this.port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public Main hostname(String hostname) { + this.hostname = hostname; + return this; + } + + public Main port(Integer port) { + this.port = port; + return this; + } + + + public YmlConfig getConfig() { + return config; + } + + public void setConfig(YmlConfig config) { + this.config = config; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Main)) { + return false; + } + Main main = (Main) o; + return check == main.check && checkMemory == main.checkMemory && checkCPU == main.checkCPU && export == main.export && Objects.equals(exportDirectory, main.exportDirectory); + } + + @Override + public int hashCode() { + return Objects.hash(check, checkMemory, checkCPU, export, exportDirectory); + } + + @Override + public String toString() { + return "{" + + " check='" + isCheck() + "'" + + ", checkMemory='" + isCheckMemory() + "'" + + ", checkCPU='" + isCheckCPU() + "'" + + ", export='" + isExport() + "'" + + ", exportDirectory='" + getExportDirectory() + "'" + + "}"; + } + + + +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/actions/Action.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/actions/Action.java new file mode 100644 index 0000000..a1f1a6f --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/actions/Action.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.actions; + +import java.util.List; + +/** + * + * @author Luís A. Bastião Silva + */ +public interface Action { + + public void execute(); + public void execute(int timeout); + public Integer getExecutions(); + + public List getMonitor(); + public Integer getTimeout(); +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/actions/imp/ProcessRun.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/actions/imp/ProcessRun.java new file mode 100644 index 0000000..cfe9d27 --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/actions/imp/ProcessRun.java @@ -0,0 +1,217 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.actions.imp; + +import com.bmdsoftware.monitor.resourcemonitor.Main; +import com.bmdsoftware.monitor.resourcemonitor.actions.Action; +import org.buildobjects.process.ProcBuilder; +import org.buildobjects.process.ProcResult; +import org.buildobjects.process.StreamConsumer; +import org.buildobjects.process.TimeoutException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * ProcessRun: run the process/execute an action + * + * @author Luís A. Bastião Silva + */ +public class ProcessRun implements Action { + private static Logger logger = LoggerFactory.getLogger(Main.class); + + + private String name = null; + private String cmd = null; + private Integer timeout = null; + private List monitor = null; + private Integer executions = null; + + /** + * Execute the process + */ + public void execute( ) { + + try { + logger.debug("Executing the following cmd: " + cmd); + System.out.println("Executing: " + cmd); + String[] args = cmd.split(" "); + List strs = new ArrayList(); + + for (int i = 1; i < args.length; i++) { + strs.add(args[i]); + } + String output = ProcBuilder.run(args[0], strs.toArray(new String[strs.size()])); + } + catch (Exception e){ + logger.error("There is a problem executing action "+ cmd, e); + } + //System.out.println(output); + } + + /** + * Execute the process with a specific timeout + */ + public void execute(int timeout) { + logger.debug("Executing "+ cmd + ", with timeout " + timeout); + ProcBuilder builder = new ProcBuilder(cmd); + try{ + ProcResult result = builder.withTimeoutMillis(timeout) + .withArg("-version") + .withOutputConsumer(new StreamConsumer() { + public void consume(InputStream stream) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + if (reader.readLine()!=null) + System.out.printf(reader.readLine()); + } + }) + .run(); + if (result.getExitValue()!=0){ + logger.error("There is a problem while running the process"); + } + + } catch (TimeoutException ex) { + logger.error("There is a problem while running the process", ex); + + } + + } + + + public ProcessRun() { + } + + public ProcessRun(String name, String cmd, Integer timeout, List monitor, Integer executions) { + this.name = name; + this.cmd = cmd; + this.timeout = timeout; + this.monitor = monitor; + this.executions = executions; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCmd() { + return this.cmd; + } + + public void setCmd(String cmd) { + this.cmd = cmd; + } + + public Integer getTimeout() { + return this.timeout; + } + + public void setTimeout(Integer timeout) { + this.timeout = timeout; + } + + public List getMonitor() { + return this.monitor; + } + + public void setMonitor(List monitor) { + this.monitor = monitor; + } + + public Integer getExecutions() { + return this.executions; + } + + public void setExecutions(Integer executions) { + this.executions = executions; + } + + public ProcessRun name(String name) { + this.name = name; + return this; + } + + public ProcessRun cmd(String cmd) { + this.cmd = cmd; + return this; + } + + public ProcessRun timeout(Integer timeout) { + this.timeout = timeout; + return this; + } + + public ProcessRun monitor(List monitor) { + this.monitor = monitor; + return this; + } + + public ProcessRun executions(Integer executions) { + this.executions = executions; + return this; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof ProcessRun)) { + return false; + } + ProcessRun processRun = (ProcessRun) o; + return Objects.equals(name, processRun.name) && Objects.equals(cmd, processRun.cmd) && Objects.equals(timeout, processRun.timeout) && Objects.equals(monitor, processRun.monitor) && Objects.equals(executions, processRun.executions); + } + + @Override + public int hashCode() { + return Objects.hash(name, cmd, timeout, monitor, executions); + } + + @Override + public String toString() { + return "{" + + " name='" + getName() + "'" + + ", cmd='" + getCmd() + "'" + + ", timeout='" + getTimeout() + "'" + + ", monitor='" + getMonitor() + "'" + + ", executions='" + getExecutions() + "'" + + "}"; + } + + + +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/conf/YmlConfig.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/conf/YmlConfig.java new file mode 100644 index 0000000..9abaa8b --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/conf/YmlConfig.java @@ -0,0 +1,212 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.conf; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import com.bmdsoftware.monitor.resourcemonitor.actions.Action; + +import com.bmdsoftware.monitor.resourcemonitor.actions.imp.ProcessRun; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.Yaml; + +/** + * + * Load the configurations for the rmjvm + * + * @author Luís A. Bastião Silva + */ +public class YmlConfig { + /** + * + */ + + private static final String ACTIONS2 = "actions"; + + /** + * + */ + + private static final String APPLICATION = "application"; + + private static Logger logger = LoggerFactory.getLogger(YmlConfig.class); + + // Link for JMX application to connect/monitoring + private String uriJmxService; + + // List of actions to execute, that will allow to increase or reduce the memory + private List actions = new ArrayList<>(); + + // Link for the tracer to send information according with the standard. + private String tracerUri; + + // Directory of the application to store dumps + private String applicationDirectory; + + private File configurationFile; + + public YmlConfig(File f) throws FileNotFoundException { + this.configurationFile = f; + this.load(f); + } + + public YmlConfig(String uriJmxService, List actions, String tracerUri) { + this.uriJmxService = uriJmxService; + this.actions = actions; + this.tracerUri = tracerUri; + } + + public void load() throws FileNotFoundException { + this.load(this.configurationFile); + } + + /** + * Load the configurations file + * + * @param f + * @throws FileNotFoundException + */ + public void load(File f) throws FileNotFoundException { + + if (!f.exists()) { + throw new FileNotFoundException(f.getAbsolutePath()); + } + Yaml yaml = new Yaml(); + + InputStream inputStream = new FileInputStream(f); + Map obj = yaml.load(inputStream); + + logger.debug("Loading configurations.. "); + + Map objActions = (Map) obj.get(APPLICATION); + this.setUriJmxService((String)objActions.get("uri")); + this.setApplicationDirectory((String)objActions.get("directory")); + + // Get actions + List objApplication = (List) obj.get(ACTIONS2); + for (Object k: objApplication){ + Map objAction = (Map )k ; + String name = (String) objAction.get("name"); + String cmd = (String)objAction.get("cmd"); + Integer timeout = (Integer) objAction.get("timeout"); + List monitor = (List)objAction.get("monitor"); + Integer executions = (Integer) objAction.get("executions"); + ProcessRun action = new ProcessRun(name, cmd, timeout, monitor, executions); + this.actions.add(action); + + } + logger.debug("Loading configurations complete. "); + + } + + private Action getAction(Map action){ + + return null; + + } + + public String getUriJmxService() { + return this.uriJmxService; + } + + public void setUriJmxService(String uriJmxService) { + this.uriJmxService = uriJmxService; + } + + public List getActions() { + return this.actions; + } + + public void setActions(List actions) { + this.actions = actions; + } + + public String getTracerUri() { + return this.tracerUri; + } + + public void setTracerUri(String tracerUri) { + this.tracerUri = tracerUri; + } + + public YmlConfig uriJmxService(String uriJmxService) { + this.uriJmxService = uriJmxService; + return this; + } + + public YmlConfig actions(List actions) { + this.actions = actions; + return this; + } + + public YmlConfig tracerUri(String tracerUri) { + this.tracerUri = tracerUri; + return this; + } + + public String getApplicationDirectory() { + return applicationDirectory; + } + + public void setApplicationDirectory(String applicationDirectory) { + this.applicationDirectory = applicationDirectory; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof YmlConfig)) { + return false; + } + YmlConfig ymlConfig = (YmlConfig) o; + return Objects.equals(uriJmxService, ymlConfig.uriJmxService) && Objects.equals(actions, ymlConfig.actions) && Objects.equals(tracerUri, ymlConfig.tracerUri); + } + + @Override + public int hashCode() { + return Objects.hash(uriJmxService, actions, tracerUri); + } + + @Override + public String toString() { + return "{" + + " uriJmxService='" + getUriJmxService() + "'" + + ", actions='" + getActions() + "'" + + ", tracerUri='" + getTracerUri() + "'" + + "}"; + } + +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/cpu/CPUMonitor.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/cpu/CPUMonitor.java new file mode 100644 index 0000000..7df10e1 --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/cpu/CPUMonitor.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.cpu; + +import java.io.IOException; + +public interface CPUMonitor { + + public void monitor() throws IOException; + +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/jmx/JMXConnection.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/jmx/JMXConnection.java new file mode 100644 index 0000000..ec9b1ff --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/jmx/JMXConnection.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.jmx; + +import java.net.MalformedURLException; +import java.util.Objects; + +import javax.management.remote.JMXServiceURL; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Connection to JMX + */ +public class JMXConnection { + private static Logger logger = LoggerFactory.getLogger(JMXConnection.class); + + private String jmxUri = null; + private JMXServiceURL jmxService; + + public JMXConnection(String jmxUri) { + this.jmxUri = jmxUri; + JMXServiceURL u = null; + try { + u = new JMXServiceURL( + jmxUri); + } catch (MalformedURLException e) { + logger.error("Error: problem with JMX connection", e); + } + jmxService = u ; + } + + + public String getJmxUri() { + return this.jmxUri; + } + + public void setJmxUri(String jmxUri) { + this.jmxUri = jmxUri; + } + + public JMXServiceURL getJmxService() { + return this.jmxService; + } + + public void setJmxService(JMXServiceURL jmxService) { + this.jmxService = jmxService; + } + + public JMXConnection jmxUri(String jmxUri) { + this.jmxUri = jmxUri; + return this; + } + + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof JMXConnection)) { + return false; + } + JMXConnection connection = (JMXConnection) o; + return Objects.equals(jmxUri, connection.jmxUri) && Objects.equals(jmxService, connection.jmxService); + } + + @Override + public int hashCode() { + return Objects.hash(jmxUri, jmxService); + } + + @Override + public String toString() { + return "{" + + " jmxUri='" + getJmxUri() + "'" + + ", jmxService='" + getJmxService() + "'" + + "}"; + } + + + +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/CreateHeapDump.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/CreateHeapDump.java new file mode 100644 index 0000000..d88da2b --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/CreateHeapDump.java @@ -0,0 +1,172 @@ +package com.bmdsoftware.monitor.resourcemonitor.memory; + + +import com.bmdsoftware.monitor.resourcemonitor.memory.TextTree; +import com.sun.management.HotSpotDiagnosticMXBean; +import org.netbeans.lib.profiler.heap.Heap; +import org.netbeans.lib.profiler.heap.HeapFactory; + +import javax.management.JMX; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.gridkit.jvmtool.heapdump.HeapHistogram; +import org.gridkit.jvmtool.heapdump.HeapWalker; + +import org.netbeans.lib.profiler.heap.Instance; +import org.netbeans.lib.profiler.heap.JavaClass; +import java.util.Date; + +@SuppressWarnings("restriction") +public class CreateHeapDump +{ + public static void main(String[] args) throws Exception + { + String host = "localhost"; + String port = "3333"; + + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/jmxrmi"); + JMXConnector jmxc = JMXConnectorFactory.connect(url, null); + MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); + ObjectName mbeanName = new ObjectName("com.sun.management:type=HotSpotDiagnostic"); + HotSpotDiagnosticMXBean bean = JMX.newMBeanProxy(mbsc, mbeanName, HotSpotDiagnosticMXBean.class, true); + + String fileName = "heap_dump_" + new SimpleDateFormat("dd.MM.yyyy HH.mm.ss").format(new Date()) + ".hprof"; + boolean onlyLiveObjects = false; + bean.dumpHeap(fileName, onlyLiveObjects); + + Heap heap = HeapFactory.createFastHeap(new File("c:/Users/bastiao/Projects/dicoogle/dicoogle/target/"+fileName)); + dumpComponentTree(heap); + + } + + public static void dumpComponentTree(Heap heap) { + + Set compClasses = new HashSet(); + Set roots = new HashSet(); + Map> links = new HashMap>(); + + // Collect all subclasses of javax.faces.component.UIComponent + for(JavaClass jc: heap.getAllClasses()) { + if (isComponent(jc)) { + compClasses.add(jc); + } + } + + System.out.println("UIComponent classes: " + compClasses.size()); + + int total = 0; + + // Scan whole heap in search for UIComponent instances + for(Instance i: heap.getAllInstances()) { + if (!compClasses.contains(i.getJavaClass())) { + continue; + } + ++total; + + // For each node find root and retain it in roots collection + Instance v = HeapWalker.valueOf(i, "compositeParent"); + v = v != null ? v : HeapWalker.valueOf(i, "parent"); + if (v == null) { + roots.add(i); + } + else { + // collect parent-to-child relations + // as they are hard to extract + // from parent component instance + if (!links.containsKey(v)) { + links.put(v, new ArrayList()); + } + links.get(v).add(i); + } + } + + System.out.println("Found " + roots.size() + " component tree roots and " + total + " nodes in total"); + + // Report tree for each root UIComponent found before + for(Instance root: roots) { + HeapHistogram hh = new HeapHistogram(); + // links variable contains all edges in component graphs identified during heap scan + collect(hh, root, links); + System.out.println(); + System.out.println(root.getInstanceId()); + System.out.println(hh.formatTop(100)); + System.out.println(); + // Dump may contain partial trees + // Report only reasonably large object clusters + if (hh.getTotalCount() > 10) { + printTree(root, links); + break; + } + } + } + + private static void printTree(Instance root, Map> links) { + TextTree tree = tree(root, links); + System.out.println(tree.printAsTree()); + } + + // TextTree is a helper class to output ASCII formated tree + private static TextTree tree(Instance node, Map> links) { + List c = new ArrayList(); + List cc = links.get(node); + if (cc != null) { + for(Instance i: cc) { + c.add(tree(i, links)); + } + } + return display(node, c.toArray(new TextTree[0])); + } + + private static TextTree display(Instance node, TextTree[] children) { + String nodeType = simpleName(node.getJavaClass().getName()); + String info = "id:" + HeapWalker.valueOf(node, "id"); + String el = HeapWalker.valueOf(node, "txt.literal"); + if (el != null) { + info += " el:" + el.replace('\n', ' '); + } + TextTree c = TextTree.t("#", children); + + return children.length == 0 + ? TextTree.t(nodeType, TextTree.t(info)) + : TextTree.t(nodeType, TextTree.t(info), c); + } + + private static void collect(HeapHistogram h, Instance node, Map> links) { + h.feed(node); + List cc = links.get(node); + if (cc != null) { + for(Instance i: cc) { + collect(h, i, links); + } + } + } + + private static String simpleName(String name) { + int c = name.lastIndexOf('.'); + return c < 0 ? name : name.substring(c + 1); + } + + public static boolean isComponent(JavaClass type) { + if (type.getName().contains("dicoogle")) { + return true; + } + else if (type.getSuperClass() != null) { + return isComponent(type.getSuperClass()); + } + else { + return false; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/DifferencialMem.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/DifferencialMem.java new file mode 100644 index 0000000..66fd306 --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/DifferencialMem.java @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.memory; + +import java.util.Map; + +/** + * Class that allows to differencial two memory dumps + */ +public class DifferencialMem { + + // default increase ram + private Long INCREASE_MEM = (long) (20 * 1024 * 1024); // 20MB; + + private MemoryDump dump1; + private MemoryDump dump2; + + private Long diffSizeAlarmTrigger = INCREASE_MEM; + + public DifferencialMem(MemoryDump dump1, MemoryDump dump2) { + this.dump1 = dump1; + this.dump2 = dump2; + } + + public Long getDiffSizeAlarmTrigger() { + return diffSizeAlarmTrigger; + } + + public void setDiffSizeAlarmTrigger(Long diffSizeAlarmTrigger) { + this.diffSizeAlarmTrigger = diffSizeAlarmTrigger; + } + + /** + * Check if there are significative changes between dump1 and dump2 + * @return + */ + public boolean isThereSignificativeIncrease() { + return false; + } + /** + * Get the objects that has the most significative increase + * @return + */ + public Map getIncreasedObjects(){ + return null; + } + + + /** + * Get the objects that was released between two memory dumps + * @return + */ + public Map getReleasedObjects(){ + return null; + } + + + + + +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryAnalysisUtil.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryAnalysisUtil.java new file mode 100644 index 0000000..9e0fc1d --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryAnalysisUtil.java @@ -0,0 +1,258 @@ +package com.bmdsoftware.monitor.resourcemonitor.memory; + +import static org.gridkit.jvmtool.heapdump.HeapWalker.valueOf; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import com.bmdsoftware.monitor.resourcemonitor.memory.TextTable; +import com.sun.management.HotSpotDiagnosticMXBean; +import org.gridkit.jvmtool.heapdump.HeapClusterAnalyzer; +import org.gridkit.jvmtool.heapdump.HeapClusterAnalyzer.ClusterDetails; +import org.gridkit.jvmtool.heapdump.HeapHistogram; +import org.gridkit.jvmtool.heapdump.HeapHistogram.ClassRecord; +import org.gridkit.jvmtool.heapdump.StringCollector; + +import org.netbeans.lib.profiler.heap.Heap; +import org.netbeans.lib.profiler.heap.HeapFactory; +import org.netbeans.lib.profiler.heap.Instance; +import org.netbeans.lib.profiler.heap.JavaClass; + +import javax.management.JMX; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +public class MemoryAnalysisUtil { + + public static Heap heap; + + public static void main(String [] args) throws Exception { + String host = "localhost"; + String port = "3333"; + + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/jmxrmi"); + JMXConnector jmxc = JMXConnectorFactory.connect(url, null); + MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); + ObjectName mbeanName = new ObjectName("com.sun.management:type=HotSpotDiagnostic"); + HotSpotDiagnosticMXBean bean = JMX.newMBeanProxy(mbsc, mbeanName, HotSpotDiagnosticMXBean.class, true); + + String fileName = "heap_dump_" + new SimpleDateFormat("dd.MM.yyyy HH.mm.ss").format(new Date()) + ".hprof"; + boolean onlyLiveObjects = false; + bean.dumpHeap(fileName, onlyLiveObjects); + + heap = HeapFactory.createFastHeap(new File("c:/Users/bastiao/Projects/dicoogle/dicoogle/target/"+fileName)); + + reportStrings(); + printHistogram(); + + } + + public static void initHeapDump() throws IOException { + String dumppath = ""; // path to dump file + heap = HeapFactory.createFastHeap(new File(dumppath)); + } + + /** Reports retained size of string object in dump */ + public static void reportStrings() { + StringCollector collector = new StringCollector(); + collector.collect(heap); + System.out.println(collector); + } + + /** + * Create "jmap -histo" like class histogram from dump + */ + public static void printHistogram() { + StringCollector collector = new StringCollector(); + HeapHistogram histo = new HeapHistogram(); + collector.collect(heap, histo); + List ht = new ArrayList(histo.getHisto()); + ht.add(collector.asClassRecord()); + Collections.sort(ht, HeapHistogram.BY_SIZE); + TextTable tt = new TextTable(); + int n = 0; + for(ClassRecord cr: ht.subList(0, 10)) { + tt.addRow("" + (++n), " " + cr.getTotalSize(), " " + cr.getInstanceCount(), " " + cr.getClassName()); + + } + System.out.println(tt.formatTextTableUnbordered(1000)); + } + + /** + * This example finds and reports Hibernate entities in dump. + */ + public static void printEnties() throws IOException { + + Map histo = new TreeMap(); + + JavaClass jc = heap.getJavaClassByName("org.hibernate.engine.spi.EntityEntry"); + for(Instance i: jc.getInstances()) { + try { + String name = "" + valueOf(i, "entityName"); +// String rowId = "" + valueOf(i, "rowId"); + System.out.println(i.getInstanceId() + "\t" + name); + int n = histo.containsKey(name) ? histo.get(name) : 0; + histo.put(name, n + 1); + } + catch (IllegalArgumentException e) { + System.err.println(e); + } + } + + System.out.println(); + for(String type: histo.keySet()) { + System.out.println(type + "\t" + histo.get(type)); + } + } + + /** + * This example extract information related to infinispan + * caches from dump. + */ + public void printCaches() throws IOException { + + HeapClusterAnalyzer hca = new HeapClusterAnalyzer(heap); + hca.addEntryPoint("(**.CacheImpl).dataContainer.entries"); + hca.blackList("(**.DefaultDataContainer$*)"); + hca.blackList("(java.lang.reflect.**)"); + hca.blackList("(**.TransactionImple)"); + hca.blackList("(**.BoundedConcurrentHashMap$HashEntry).*"); + hca.blackList("(**.BoundedConcurrentHashMap$LRU)"); + hca.prepare(); + + Map histo = new TreeMap(); + + JavaClass jc = heap.getJavaClassByName("org.infinispan.CacheImpl"); + for(Instance i: jc.getInstances()) { + try { + String name = "" + valueOf(i, "name"); + ClusterDetails cluster = hca.feed(i); + ClassRecord classInfo = cluster.getHistogram().getClassInfo("org.infinispan.util.concurrent.BoundedConcurrentHashMap$HashEntry"); + System.out.println(i.getInstanceId() + "\t" + name + "\t" + (classInfo == null ? "0" : classInfo.getInstanceCount())); + int n = histo.containsKey(name) ? histo.get(name) : 0; + histo.put(name, n + 1); + } + catch (IllegalArgumentException e) { + System.err.println(e); + } + } + } + + /** + * This examples calculates retained set for active HTTP sessions. + * It also report top 50 entries of class histogram for each cluster. + * + * @throws IOException + */ + public void printSessionClusters() throws IOException { + HeapClusterAnalyzer analyzer = new HeapClusterAnalyzer(heap); + + analyzer.useBreadthSearch(); + + analyzer.addEntryPoint("(**.StandardSession)"); + + // this is a list of singleton objects we do not care + loadSingletons(analyzer, "src/test/resources/singletons-list.txt"); + + // below we are configuring edges we want to ignore + // while traveling heap graph + // HeapPath notation is used to define edges + analyzer.blackList("(+java.lang.Enum)"); + analyzer.blackList("(**.StandardSession).manager"); + analyzer.blackList("(**.LogImpl)"); + analyzer.blackList("(**.LogEvsAction*)"); + analyzer.blackList("(**.SessionFactoryImpl)"); + analyzer.blackList("(**.Settings)"); + analyzer.blackList("(**.TransactionEnvironmentImpl)"); + analyzer.blackList("(**.InjectedDataSourceConnectionProvider)"); + analyzer.blackList("(**.WrapperDataSource)"); + analyzer.blackList("(**.JdbcServicesImpl)"); + analyzer.blackList("(**).log"); + analyzer.blackList("(**.JBossLogManagerLogger)"); + analyzer.blackList("(java.lang.reflect.Method)"); + analyzer.blackList("(java.lang.reflect.Field)"); + analyzer.blackList("(java.lang.reflect.Constructor)"); + analyzer.blackList("(java.lang.Class)"); + analyzer.blackList("(**.TransactionalAccess)"); + analyzer.blackList("(**.BytecodeProviderImpl)"); + analyzer.blackList("(**.LinkedHashMap$Entry).after"); + analyzer.blackList("(**.LinkedHashMap$Entry).before"); + analyzer.blackList("(sun.reflect.**)"); + analyzer.blackList("(+java.lang.Throwable)"); + analyzer.blackList("(+java.lang.Thread)"); + analyzer.blackList("(java.lang.ref.Finalizer)"); + analyzer.blackList("(org.jboss.jca.core.connectionmanager.pool.strategy.OnePool)"); + analyzer.blackList("(**.ReentrantLock)"); + analyzer.blackList("(**.SemaphoreArrayListManagedConnectionPool)"); + analyzer.blackList("(**.ImmediateValue).value"); + analyzer.blackList("(org.infinispan.**)"); + analyzer.blackList("(java.security.**)"); + + analyzer.prepare(); + + System.out.println("Scanning"); + + Iterable scanList = heap.getAllInstances(); + long lastId = 0; + for(Instance i: scanList) { + long id = i.getInstanceId(); + if (id < lastId) { + System.out.println(lastId + " | " + id); + } + lastId = id; + } + for(Instance i: scanList) { + ClusterDetails c = analyzer.feed(i); + if (c != null) { + System.out.println("Cluster " + c.getRootInstance().getInstanceId()); + System.out.println(c.getHistogram().formatTop(50)); + System.out.println(); + } + } + + System.out.println("\n\nShared error margin: " + analyzer.getSharedErrorMargin()); + System.out.println("Shared objects"); + System.out.println(analyzer.getSharedSummary().formatTop(100)); + + System.out.println("\n\nCLUSTERS BY SIZE\n"); + + List list = new ArrayList(analyzer.getClusters()); + Collections.sort(list, new Comparator() { + @Override + public int compare(ClusterDetails o1, ClusterDetails o2) { + return ((Long)o2.getHistogram().getTotalSize()).compareTo(o1.getHistogram().getTotalSize()); + } + }); + + for(ClusterDetails c: list) { + System.out.println("Cluster " + c.getRootInstance().getInstanceId()); + System.out.println(c.getHistogram().formatTop(50)); + System.out.println(); + } + System.out.println(list.size() + " clusters"); + } + + private void loadSingletons(HeapClusterAnalyzer hca, String path) throws IOException { + BufferedReader br = new BufferedReader(new FileReader(path)); + String line; + while((line = br.readLine()) != null) { + line = line.trim(); + if (line.length() > 0) { + hca.addTokenToBlacklist(line); + } + } + } +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryChecker.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryChecker.java new file mode 100644 index 0000000..7c34043 --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryChecker.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.memory; + +import org.netbeans.lib.profiler.heap.Heap; + +import java.io.IOException; + +public interface MemoryChecker { + public void monitor() throws IOException ; + public Heap getHeap(); + +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryDump.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryDump.java new file mode 100644 index 0000000..7fcbe43 --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryDump.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.memory; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.gridkit.jvmtool.heapdump.HeapHistogram; +import org.gridkit.jvmtool.heapdump.StringCollector; +import org.gridkit.jvmtool.heapdump.HeapHistogram.ClassRecord; + +public class MemoryDump { + + + private File dumpMem; + + public MemoryDump(File dumpMem){ + + + } + + + public Long getTotalRamSize(){ + return 0L; + } + + public Object getHighestMemObject(int rank){ + return rank; + } + + + + +} \ No newline at end of file diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryMonitor.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryMonitor.java new file mode 100644 index 0000000..a621046 --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/MemoryMonitor.java @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.memory; + +import java.io.File; +import java.util.Objects; + +import com.bmdsoftware.monitor.resourcemonitor.jmx.JMXConnection; + +import static org.gridkit.jvmtool.heapdump.HeapWalker.valueOf; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Path; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import com.bmdsoftware.monitor.resourcemonitor.memory.TextTable; +import com.sun.management.HotSpotDiagnosticMXBean; +import org.gridkit.jvmtool.heapdump.HeapClusterAnalyzer; +import org.gridkit.jvmtool.heapdump.HeapClusterAnalyzer.ClusterDetails; +import org.gridkit.jvmtool.heapdump.HeapHistogram; +import org.gridkit.jvmtool.heapdump.HeapHistogram.ClassRecord; +import org.gridkit.jvmtool.heapdump.StringCollector; + +import org.netbeans.lib.profiler.heap.Heap; +import org.netbeans.lib.profiler.heap.HeapFactory; +import org.netbeans.lib.profiler.heap.Instance; +import org.netbeans.lib.profiler.heap.JavaClass; + +import javax.management.JMX; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import org.netbeans.lib.profiler.heap.HeapFactory; + +/** + * MemoryMonitor: monitoring the memory + */ +public class MemoryMonitor { + + private JMXConnection jmx; + public Heap heap; + + public MemoryMonitor() { + } + + public MemoryMonitor(JMXConnection jmx) { + this.jmx = jmx; + } + + /** + * + * @throws IOException + * @throws MalformedObjectNameException + */ + public void initHeapDump(File dumpFileDir) throws IOException, MalformedObjectNameException { + //heap = HeapFactory.createFastHeap(dumpFile); + JMXConnector jmxc = JMXConnectorFactory.connect(jmx.getJmxService(), null); + MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); + ObjectName mbeanName = new ObjectName("com.sun.management:type=HotSpotDiagnostic"); + HotSpotDiagnosticMXBean bean = JMX.newMBeanProxy(mbsc, mbeanName, HotSpotDiagnosticMXBean.class, true); + + String fileName = "heap_dump_" + new SimpleDateFormat("dd.MM.yyyy HH.mm.ss").format(new Date()) + ".hprof"; + boolean onlyLiveObjects = false; + bean.dumpHeap(fileName, onlyLiveObjects); + File dumpFile = new File(dumpFileDir.getAbsolutePath()+File.separator+fileName); + heap = HeapFactory.createFastHeap(dumpFile); + //heap = HeapFactory.createFastHeap(dumpFile); + dumpFile.deleteOnExit(); + + } + + /** Reports retained size of string object in dump */ + public String reportStrings() { + StringCollector collector = new StringCollector(); + collector.collect(heap); + //System.out.println(collector); + return collector.toString(); + } + + + /** + * Create "jmap -histo" like class histogram from dump + */ + public String printHistogram() { + StringCollector collector = new StringCollector(); + HeapHistogram histo = new HeapHistogram(); + collector.collect(heap, histo); + List ht = new ArrayList(histo.getHisto()); + ht.add(collector.asClassRecord()); + Collections.sort(ht, HeapHistogram.BY_SIZE); + TextTable tt = new TextTable(); + int n = 0; + for(ClassRecord cr: ht.subList(0, 500)) { + tt.addRow("" + (++n), " " + cr.getTotalSize(), " " + cr.getInstanceCount(), " " + cr.getClassName()); + + } + //System.out.println(tt.formatTextTableUnbordered(1000)); + return tt.formatTextTableUnbordered(1000); + } + + + public JMXConnection getJmx() { + return this.jmx; + } + + public void setJmx(JMXConnection jmx) { + this.jmx = jmx; + } + + public MemoryMonitor jmx(JMXConnection jmx) { + this.jmx = jmx; + return this; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof MemoryMonitor)) { + return false; + } + MemoryMonitor memoryMonitor = (MemoryMonitor) o; + return Objects.equals(jmx, memoryMonitor.jmx); + } + + @Override + public int hashCode() { + return Objects.hashCode(jmx); + } + + @Override + public String toString() { + return "{" + + " jmx='" + getJmx() + "'" + + "}"; + } + +} \ No newline at end of file diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/TextTable.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/TextTable.java new file mode 100644 index 0000000..d9462b1 --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/TextTable.java @@ -0,0 +1,158 @@ +package com.bmdsoftware.monitor.resourcemonitor.memory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Class from JVM TOOLS: https://github.com/aragozin/jvm-tools/ + * + * @author Alexey Ragozin (alexey.ragozin@gmail.com) + */ +public class TextTable { + + private List rows = new ArrayList(); + private int colCount; + + public void transpone() { + int rc = rows.size(); + int cc = colCount; + + List nrows = new ArrayList(); + for(int i = 0; i != cc; ++i) { + String[] nrow = new String[cc]; + for(int j = 0; j != rc; ++i) { + nrow[j] = rows.get(j)[i]; + } + nrows.add(nrow); + } + + rows = nrows; + colCount = rc; + } + + public void addRow(String... row) { + addRow(row, false); + } + + public void addRow(List row) { + addRow(row.toArray(new String[row.size()]), false); + } + + public void addRow(List row, boolean autoGrow) { + addRow(row.toArray(new String[row.size()]), autoGrow); + } + + public void addRow(String[] row, boolean autoGrow) { + if (rows.size() == 0) { + colCount = row.length; + } + if (row.length > colCount) { + if (autoGrow) { + extendRows(row.length); + } + else { + throw new IllegalArgumentException("Row is longer than table"); + } + } + rows.add(Arrays.copyOf(row, colCount)); + } + + private void extendRows(int length) { + for(int i = 0; i != rows.size(); ++i) { + rows.set(i, Arrays.copyOf(rows.get(i), length)); + } + colCount = length; + } + + public void addColumnRight(List col) { + addColumnRight(col.toArray(new String[col.size()])); + } + + public void addColumnRight(String... col) { + if (col.length > rows.size()) { + throw new IllegalArgumentException("Column is taller than table"); + } + colCount += 1; + for(int i = 0; i != rows.size(); ++i) { + String[] row = rows.get(i); + row = Arrays.copyOf(row, colCount); + if (col.length > i) { + row[colCount - 1] = col[i]; + } + rows.set(i, row); + } + } + + public void addColumnLeft(List col) { + addColumnLeft(col.toArray(new String[col.size()])); + } + + public void addColumnLeft(String[] col) { + if (col.length > rows.size()) { + throw new IllegalArgumentException("Column is taller than table"); + } + colCount += 1; + for(int i = 0; i != rows.size(); ++i) { + String[] row = rows.get(i); + String[] nrow = new String[colCount]; + System.arraycopy(row, 0, nrow, 1, row.length); + if (col.length > i) { + nrow[0] = col[i]; + } + rows.set(i, nrow); + } + } + + public String formatTextTable(int maxCellWidth) { + return formatTable(rows, maxCellWidth, true); + } + + public String formatTextTableUnbordered(int maxCellWidth) { + return formatTable(rows, maxCellWidth, false); + } + + private String formatTable(List content, int maxCell, boolean table) { + int[] width = new int[content.get(0).length]; + for(String[] row: content) { + for(int i = 0; i != row.length; ++i) { + width[i] = Math.min(Math.max(width[i], (row[i] == null ? 0 : row[i].length())), maxCell); + } + } + + StringBuilder sb = new StringBuilder(); + boolean header = table; + for(String[] row: content) { + for(int i = 0; i != width.length; ++i) { + String cell = row[i] == null ? "" : row[i]; + if (cell.length() > width[i]) { + cell = cell.substring(0, width[i] - 3) + "..."; + } + sb.append(cell); + for(int s = 0; s != width[i] - cell.length(); ++s) { + sb.append(' '); + } + if (table) { + sb.append('|'); + } + } + if (table) { + sb.setLength(sb.length() - 1); + } + sb.append('\n'); + if (header) { + header = false; + for(int n: width) { + for(int i = 0; i != n; ++i) { + sb.append('-'); + } + sb.append('+'); + } + sb.setLength(sb.length() - 1); + sb.append('\n'); + } + } + + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/TextTree.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/TextTree.java new file mode 100644 index 0000000..f28c99d --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/TextTree.java @@ -0,0 +1,74 @@ +package com.bmdsoftware.monitor.resourcemonitor.memory; + +import java.util.Arrays; + +/** + * + * Class from JVM TOOLS: https://github.com/aragozin/jvm-tools/ + * + * + * Helper class for dumping trees. Used for diagnostic + * @author Alexey Ragozin (alexey.ragozin@gmail.com) + */ +public class TextTree { + + public static TextTree t(String text, TextTree... children) { + return new TextTree(text, children); + } + + private String text; + private TextTree[] children; + + public TextTree(String text, TextTree... children) { + this.text = text; + this.children = children; + } + + public String printAsTree() { + StringBuilder sb = new StringBuilder(); + printTreeNode(sb, "", this); + return sb.toString(); + } + + private static void printTreeNode(StringBuilder sb, String prefix, TextTree node) { + String t = String.valueOf(node.text); + sb.append(t); + if (node.children.length == 0) { + sb.append('\n'); + } + else { + String npref = prefix + blank(t.length()) + "| "; + String cpref = prefix + blank(t.length()); + if (node.children.length == 1) { + sb.append("--"); + npref = cpref + " "; + } + else { + sb.append("+-"); + } + printTreeNode(sb, npref , node.children[0]); + for(int i = 1; i < node.children.length; ++i) { + sb.append(cpref); + if (i < node.children.length - 1) { + sb.append("+-"); + printTreeNode(sb, npref , node.children[i]); + } + else { + sb.append("\\-"); + printTreeNode(sb, cpref + " " , node.children[i]); + } + } + } + } + + private static String blank(int n) { + char[] ch = new char[n]; + Arrays.fill(ch, ' '); + return new String(ch); + } + + @Override + public String toString() { + return text + (children.length == 0 ? "" : Arrays.toString(children)); + } +} \ No newline at end of file diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/imp/MemoryCheckImp.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/imp/MemoryCheckImp.java new file mode 100644 index 0000000..852d09f --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/memory/imp/MemoryCheckImp.java @@ -0,0 +1,234 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.memory.imp; + +import com.bmdsoftware.monitor.resourcemonitor.jmx.JMXConnection; +import com.bmdsoftware.monitor.resourcemonitor.memory.MemoryAnalysisUtil; +import com.bmdsoftware.monitor.resourcemonitor.memory.MemoryChecker; +import com.sun.management.HotSpotDiagnosticMXBean; +import org.netbeans.lib.profiler.heap.Heap; +import org.netbeans.lib.profiler.heap.HeapFactory; + +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.JMX; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.openmbean.CompositeData; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import java.io.File; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.text.SimpleDateFormat; +import java.util.Date; + +import static com.bmdsoftware.monitor.resourcemonitor.memory.MemoryAnalysisUtil.printHistogram; +import static com.bmdsoftware.monitor.resourcemonitor.memory.MemoryAnalysisUtil.reportStrings; + + +/** + * Memory Checker Implementation + */ +public class MemoryCheckImp implements MemoryChecker { + + private JMXConnection jmxConnection; + private String nameHeapFile; + + private Long totalMemory; + + + private Heap heap; + + + public MemoryCheckImp(JMXConnection jmxConnection, String nameHeapFile) { + this.jmxConnection = jmxConnection; + this.nameHeapFile = nameHeapFile; + } + + + + public void monitor() throws IOException { + JMXServiceURL url = this.jmxConnection.getJmxService(); + JMXConnector jmxc = JMXConnectorFactory.connect(url, null); + MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); + + ObjectName mbeanName = null; + try { + mbeanName = new ObjectName("com.sun.management:type=HotSpotDiagnostic"); + } catch (MalformedObjectNameException e) { + e.printStackTrace(); + } + HotSpotDiagnosticMXBean bean = JMX.newMBeanProxy(mbsc, mbeanName, HotSpotDiagnosticMXBean.class, true); + + String fileName = "heap_dump_" + new SimpleDateFormat("dd.MM.yyyy HH.mm.ss").format(new Date()) + ".hprof"; + boolean onlyLiveObjects = false; + bean.dumpHeap(fileName, onlyLiveObjects); + + heap = HeapFactory.createFastHeap(new File(nameHeapFile + fileName)); + MemoryAnalysisUtil.heap = heap; + + + printHistogram(); + // get the memory composite information + + + //create object instances that will be used to get memory and operating system Mbean objects exposed by JMX; create variables for cpu time and system time before + Object memoryMbean = null; + Object osMbean = null; + long cpuBefore = 0; + long tempMemory = 0; + CompositeData cd = null; + + cpuBefore = Long.parseLong("100"); + + int sampleCount = 10; + + // call the garbage collector before the test using the Memory Mbean + try { + jmxc.getMBeanServerConnection().invoke(new ObjectName("java.lang:type=Memory"), "gc", null, null); + } catch (InstanceNotFoundException e) { + e.printStackTrace(); + } catch (MBeanException e) { + e.printStackTrace(); + } catch (ReflectionException e) { + e.printStackTrace(); + } catch (MalformedObjectNameException e) { + e.printStackTrace(); + } + +//create a loop to get values every second (optional) + for (int i = 0; i < sampleCount; i++) { + + //get an instance of the HeapMemoryUsage Mbean + try { + memoryMbean = jmxc.getMBeanServerConnection().getAttribute(new ObjectName("java.lang:type=Memory"), "HeapMemoryUsage"); + } catch (MBeanException e) { + e.printStackTrace(); + } catch (AttributeNotFoundException e) { + e.printStackTrace(); + } catch (InstanceNotFoundException e) { + e.printStackTrace(); + } catch (ReflectionException e) { + e.printStackTrace(); + } catch (MalformedObjectNameException e) { + e.printStackTrace(); + } + cd = (CompositeData) memoryMbean; + + //get an instance of the OperatingSystem Mbean + try { + osMbean = jmxc.getMBeanServerConnection().getAttribute(new ObjectName("java.lang:type=OperatingSystem"),"ProcessCpuTime"); + } catch (MBeanException e) { + e.printStackTrace(); + } catch (AttributeNotFoundException e) { + e.printStackTrace(); + } catch (InstanceNotFoundException e) { + e.printStackTrace(); + } catch (ReflectionException e) { + e.printStackTrace(); + } catch (MalformedObjectNameException e) { + e.printStackTrace(); + } + + //System.out.println("Used memory: " + " " + cd.get("used") + " Used cpu: " + osMbean); //print memory usage + tempMemory = tempMemory + Long.parseLong(cd.get("used").toString()); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + //get system time and cpu time from last poll + long cpuAfter = Long.parseLong(osMbean.toString()); + + long cpuDiff = cpuAfter - cpuBefore; //find cpu time between our first and last jmx poll + System.out.println("Cpu diff in milli seconds: " + cpuDiff / 1000000); //print cpu time in miliseconds + System.out.println("average memory usage is: " + tempMemory / sampleCount);//print average memory usage + } + + + public JMXConnection getJmxConnection() { + return jmxConnection; + } + + public void setJmxConnection(JMXConnection jmxConnection) { + this.jmxConnection = jmxConnection; + } + + public String getNameHeapFile() { + return nameHeapFile; + } + + public void setNameHeapFile(String nameHeapFile) { + this.nameHeapFile = nameHeapFile; + } + + + + public Heap getHeap() { + return heap; + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MemoryCheckImp that = (MemoryCheckImp) o; + + if (jmxConnection != null ? !jmxConnection.equals(that.jmxConnection) : that.jmxConnection != null) + return false; + return nameHeapFile != null ? nameHeapFile.equals(that.nameHeapFile) : that.nameHeapFile == null; + + } + + @Override + public int hashCode() { + int result = jmxConnection != null ? jmxConnection.hashCode() : 0; + result = 31 * result + (nameHeapFile != null ? nameHeapFile.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "MemoryCheckImp{" + + "jmxConnection=" + jmxConnection + + ", nameHeapFile='" + nameHeapFile + '\'' + + '}'; + } +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/utils/Consts.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/utils/Consts.java new file mode 100644 index 0000000..74d5b37 --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/utils/Consts.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.utils; + + +/** + * The constants that needs to be used in the application. + * + * @author Luís A. Bastião Silva + */ +public class Consts { + public static int ERROR_WHILE_PARSING = 1; +} diff --git a/src/main/java/com/bmdsoftware/monitor/resourcemonitor/utils/OSDetector.java b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/utils/OSDetector.java new file mode 100644 index 0000000..a630aac --- /dev/null +++ b/src/main/java/com/bmdsoftware/monitor/resourcemonitor/utils/OSDetector.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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.bmdsoftware.monitor.resourcemonitor.utils; + +public class OSDetector { + + + private static String OS = System.getProperty("os.name").toLowerCase(); + + public enum OSTYPE {WINDOWS, UNIX, MAC, UNKNOWN}; + + public static OSTYPE detectOS() { + if (isWindows()) { + return OSTYPE.WINDOWS; + + } else if (isMac()) { + return OSTYPE.MAC; + } else if (isUnix()) { + return OSTYPE.UNIX; + } else { + return OSTYPE.UNKNOWN; + } + } + + public static boolean isWindows() { + return (OS.indexOf("win") >= 0); + } + + public static boolean isMac() { + return (OS.indexOf("mac") >= 0); + } + + public static boolean isUnix() { + return (OS.indexOf("nux") >= 0); + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..87fa12d --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/src/test/java/TestAction.java b/src/test/java/TestAction.java new file mode 100644 index 0000000..d48a826 --- /dev/null +++ b/src/test/java/TestAction.java @@ -0,0 +1,23 @@ +import com.bmdsoftware.monitor.resourcemonitor.actions.imp.ProcessRun; +import com.bmdsoftware.monitor.resourcemonitor.utils.OSDetector; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TestAction { + + + private final ProcessRun processRun = new ProcessRun(); + + @Test + void run() { + String cmd = ""; + if (OSDetector.isWindows()){ + cmd = "java"; + } + else{ + cmd = "java"; + } +// processRun.execute(1000); + } +} diff --git a/src/test/java/TestMemoryMonitor.java b/src/test/java/TestMemoryMonitor.java new file mode 100644 index 0000000..a1d652d --- /dev/null +++ b/src/test/java/TestMemoryMonitor.java @@ -0,0 +1,90 @@ + +/** + * Copyright (c) 2019, BMD software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 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. + */ + +import com.bmdsoftware.monitor.resourcemonitor.actions.imp.ProcessRun; +import com.bmdsoftware.monitor.resourcemonitor.jmx.JMXConnection; +import com.bmdsoftware.monitor.resourcemonitor.memory.MemoryMonitor; +import com.bmdsoftware.monitor.resourcemonitor.utils.OSDetector; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.management.MalformedObjectNameException; + +public class TestMemoryMonitor { + + // it also could work to check if external process are working + boolean setupAJavaProces() { + return true; + } + + @Test + void testMemoryConnection() throws IOException, MalformedObjectNameException { + setupAJavaProces(); + + String hostName = "localhost"; + String portNum = "3333"; + JMXConnection con = null; + try { + con = new JMXConnection("service:jmx:rmi:///jndi/rmi://" + hostName + ":" + portNum + "/jmxrmi"); + } + catch (Exception e){ + return; + } + + // Create a temporary directory + //File myTempDir = Files.createTempDir(); + Path tempDirWithPrefix = Files.createTempDirectory("rmjvm-"); + + MemoryMonitor monitor = new MemoryMonitor(con); + monitor.initHeapDump(new File("c:/Users/bastiao/Projects/dicoogle/dicoogle/target/")); + String report = monitor.reportStrings(); + String hist = monitor.printHistogram(); + System.out.println(hist); + + } + + @Test + void testDiffMemory(){ + + // Snapshot Dump 1 + + + // Snapshot Dump 2 + + + + } +}