diff --git a/.gitignore b/.gitignore index 34e1547..8b2d751 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,24 @@ +.settings +.project +.classpath +.external* +.DS_Store +.springBeans +Thumbs.db target .idea -*.iml \ No newline at end of file +*.iml +bin +logs +**/.settings +**/.project +**/.classpath +**/.external* +**/.DS_Store +**/.springBeans +**/Thumbs.db +**/target +**/bin +**/logs +**/.idea +**/*.iml diff --git a/README.md b/README.md index 8b498b8..3f8b702 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,19 @@ or You can also specify the arguments with spaces before the ports, like this: - `mvn exec:java -Dexec.args="-pr 2222 -ph 2223 -pv 2224"` +Build and test on Mac OSX +```bash +JAVA_HOME="/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home" mvn -Dmaven.test.skip=true help:active-profiles clean package + +JAVA_HOME="/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home" MAVEN_OPTS="--add-modules jdk.jstatd,jdk.internal.jvmstat" mvn clean package exec:java -Dexec.args="-pr 2222 -ph 2223 -pv 2224" + +JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk-10.jdk/Contents/Home" MAVEN_OPTS="--add-modules jdk.jstatd,jdk.internal.jvmstat" mvn -Dmaven.test.skip=true help:active-profiles clean package exec:java -Dexec.args="-pr 2222 -ph 2223 -pv 2224" + +JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home" MAVEN_OPTS="--add-modules jdk.jstatd,jdk.internal.jvmstat" mvn -Dmaven.test.skip=true help:active-profiles clean package exec:java -Dexec.args="-pr 2222 -ph 2223 -pv 2224" + +JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home" mvn -Dmaven.test.skip=true help:active-profiles clean package exec:java -Dexec.args="-pr 2222 -ph 2223 -pv 2224" +``` + # Usage in Docker In this section we will consider using those 3 ports as example, don't forget to replace them with yours: `2222` for `pr`, `2223` for `ph` and `2224` for `pv`. @@ -37,6 +50,19 @@ And inside the Docker image `myimage`, `ejstatd` should be launched from a scrip Then you could access this `ejstatd` using JVisualVM running on your Desktop PC for example adding a "Remote Host" specifying your Docker hostname as "Host name" and adding a "Custom jstatd Connections" (in the "Advanced Settings") by setting "2222" to "Port". +# Usage with Openshift (Production case, assuming that you cannot restart POD) +1. Download `ejstatd` & corresponding `tools.jar` (from java folder) to the machine. (You can use [Droppy Tool](https://github.com/stackp/Droopy) or even wget if you have public facing storage ) for that. +2. Run it: +```bash +java -Djava.rmi.server.hostname=localhost -cp "ejstatd-1.0.0.jar:tools1.8.jar" com.github.anthony_o.ejstatd.EJstatd -pr2222 -ph2223 -pv2224 +``` +3. On the VisualVm machine - login to openshift & enable port forwarding: +```bash +oc login
--token= +oc port-forward 2222 2223 2224 +``` +4. Open VisualVm & connect jstat to local machine port 2222 + # Prerequisites 1. Install a [JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 1. [Install Maven](http://maven.apache.org/install.html) (make sure its `bin` folder is in the `PATH`) @@ -44,4 +70,4 @@ Then you could access this `ejstatd` using JVisualVM running on your Desktop PC 1. `cd` into the project and create the package using `mvn package` command # Thanks -This program is based on JDK 7's `jstatd` (using sources from its [Mercurial repository](http://hg.openjdk.java.net/jdk7u/jdk7u/jdk)) and highly inspired by [jdonofrio728](https://github.com/jdonofrio728/)'s [JakestatD](https://github.com/jdonofrio728/jakestatd). \ No newline at end of file +This program is based on JDK 7's `jstatd` (using sources from its [Mercurial repository](http://hg.openjdk.java.net/jdk7u/jdk7u/jdk)) and highly inspired by [jdonofrio728](https://github.com/jdonofrio728/)'s [JakestatD](https://github.com/jdonofrio728/jakestatd). diff --git a/pom.xml b/pom.xml index 220dace..d8c438c 100644 --- a/pom.xml +++ b/pom.xml @@ -1,34 +1,16 @@ - + 4.0.0 - com.github.anthony-o ejstatd - 1.0.0 - jar Enhanced jstatd - - - UTF-8 - 1.5 - - - - - - com.sun - tools - 1.6 - system - ${java.home}/../lib/tools.jar - - + com.github.anthony-o + jar + 1.0.0 maven-compiler-plugin - 3.5.1 ${java.version} ${java.version} @@ -37,7 +19,6 @@ maven-jar-plugin - 2.6 @@ -46,18 +27,31 @@ lib com.github.anthony_o.ejstatd.EJstatd + + java${java.version} + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source-of-specific-java-version + generate-sources + add-source + + src/main/java${java.version} + + + + org.codehaus.mojo exec-maven-plugin - 1.5.0 - - java - + java @@ -67,5 +61,100 @@ + + + build-helper-maven-pluginorg.codehaus.mojo3.0.0 + exec-maven-pluginorg.codehaus.mojo1.6.0 + maven-compiler-plugin3.8.0 + maven-jar-plugin3.1.1 + + + + + + + ejstatd-default-java8 + + [1.8,9) + ${java.home}/../lib/tools.jar + + + + com.sun + tools + 1.8 + system + ${java.home}/../lib/tools.jar + + + + 8 + + + + ejstatd-java9-to-10 + + [9,10] + + + + + maven-compiler-plugin + + + -Xdiags:verbose + -Xlint:deprecation + + --add-modules=jdk.jstatd,jdk.internal.jvmstat + + --add-exportsjdk.jstatd/sun.jvmstat.monitor.remote=ALL-UNNAMED + + --add-exportsjdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED + + --add-exportsjdk.internal.jvmstat/sun.jvmstat.monitor.event=ALL-UNNAMED + + + + + + + 9 + + + + ejstatd-java11-and-newer + + [11,) + + + + + maven-compiler-plugin + + + -Xdiags:verbose + -Xlint:deprecation + + --add-modules=jdk.jstatd,jdk.internal.jvmstat + + --add-exportsjdk.jstatd/sun.jvmstat.monitor.remote=ALL-UNNAMED + + --add-exportsjdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED + + --add-exportsjdk.internal.jvmstat/sun.jvmstat.monitor.event=ALL-UNNAMED + + + + + + + 11 + + + + + + UTF-8 + \ No newline at end of file diff --git a/src/main/java/com/github/anthony_o/ejstatd/EJstatd.java b/src/main/java/com/github/anthony_o/ejstatd/EJstatd.java index a55d369..0b5fbd7 100644 --- a/src/main/java/com/github/anthony_o/ejstatd/EJstatd.java +++ b/src/main/java/com/github/anthony_o/ejstatd/EJstatd.java @@ -32,6 +32,8 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.rmi.Naming; import java.rmi.RMISecurityManager; import java.rmi.RemoteException; @@ -47,7 +49,7 @@ * provided through an RMI interface. * * @author Brian Doherty - * @since 1.5 + * @since 1.7+ */ public class EJstatd { @@ -59,7 +61,7 @@ private static void printUsage() { System.err.println("usage: ejstatd [-nr] [-pr port] [-ph port] [-pv port] [-n rminame]"); } - static void bind(String name, RemoteHostImpl remoteHost) + static void bind(final String name, final RemoteHostImpl remoteHost) throws RemoteException, MalformedURLException, Exception { try { @@ -85,7 +87,7 @@ static void bind(String name, RemoteHostImpl remoteHost) } } - public static void main(String[] args) throws IOException, URISyntaxException, ClassNotFoundException { + public static void main(final String[] args) throws IOException, URISyntaxException, ClassNotFoundException { String rminame = null; int argc = 0; int remoteHostPort = Integer.parseInt(System.getProperty("ejstatd.remoteHost.port", "0")); @@ -199,9 +201,13 @@ public static void main(String[] args) throws IOException, URISyntaxException, C for (Class klass : classesToAllow) { CodeSource codeSource = klass.getProtectionDomain().getCodeSource(); if (codeSource != null) { + // System.err.println("allow " + codeSource.getLocation().toURI().toString()); codebasesToAllow.add(codeSource.getLocation().toURI().toString()); } } + if (!codebasesToAllow.contains("jrt:/jdk.internal.jvmstat") && codebasesToAllow.contains("jrt:/jdk.jstatd")) { + codebasesToAllow.add("jrt:/jdk.internal.jvmstat"); + } FileOutputStream policyOutputStream = new FileOutputStream(policyFile); try { @@ -215,6 +221,8 @@ public static void main(String[] args) throws IOException, URISyntaxException, C policyOutputStream.close(); } System.setProperty("java.security.policy", policyFile.toString()); + System.err.println("java.security.policy=" + policyFile.toString()); + System.err.println(new String(Files.readAllBytes(Paths.get(policyFile.toString())))); } if (System.getSecurityManager() == null) { diff --git a/src/main/java/com/github/anthony_o/ejstatd/RemoteHostImpl.java b/src/main/java1.8/com/github/anthony_o/ejstatd/RemoteHostImpl.java similarity index 72% rename from src/main/java/com/github/anthony_o/ejstatd/RemoteHostImpl.java rename to src/main/java1.8/com/github/anthony_o/ejstatd/RemoteHostImpl.java index d1cc1cf..28cb13b 100644 --- a/src/main/java/com/github/anthony_o/ejstatd/RemoteHostImpl.java +++ b/src/main/java1.8/com/github/anthony_o/ejstatd/RemoteHostImpl.java @@ -55,66 +55,60 @@ public class RemoteHostImpl implements RemoteHost, HostListener { private MonitoredHost monitoredHost; - private Set activeVms; + private final Set activeVms; public RemoteHostImpl() throws MonitorException { try { - monitoredHost = MonitoredHost.getMonitoredHost("localhost"); + this.monitoredHost = MonitoredHost.getMonitoredHost("localhost"); } catch (URISyntaxException e) { } - activeVms = monitoredHost.activeVms(); - monitoredHost.addHostListener(this); + this.activeVms = this.monitoredHost.activeVms(); + this.monitoredHost.addHostListener(this); } - public RemoteVm attachVm(int lvmid, String mode) - throws RemoteException, MonitorException { - RemoteVm stub = null; - StringBuffer sb = new StringBuffer(); + public RemoteVm attachVm(final int lvmid, final String mode) throws RemoteException, MonitorException { + RemoteVm stub; + final StringBuilder sb = new StringBuilder(); sb.append("local://").append(lvmid).append("@localhost"); if (mode != null) { - sb.append("?mode=" + mode); + sb.append("?mode=").append(mode); } - - String vmidStr = sb.toString(); + final String vmidStr = sb.toString(); try { - VmIdentifier vmid = new VmIdentifier(vmidStr); - MonitoredVm mvm = monitoredHost.getMonitoredVm(vmid); - RemoteVmImpl rvm = new RemoteVmImpl((BufferedMonitoredVm)mvm); + final VmIdentifier vmid = new VmIdentifier(vmidStr); + final MonitoredVm mvm = this.monitoredHost.getMonitoredVm(vmid); + final RemoteVmImpl rvm = new RemoteVmImpl((BufferedMonitoredVm)mvm); stub = (RemoteVm) UnicastRemoteObject.exportObject(rvm, Integer.parseInt(System.getProperty("ejstatd.remoteVm.port", "0"))); } - catch (URISyntaxException e) { - throw new RuntimeException("Malformed VmIdentifier URI: " - + vmidStr, e); + catch (final URISyntaxException e) { + throw new RuntimeException("Malformed VmIdentifier URI: " + vmidStr, e); } return stub; } - public void detachVm(RemoteVm rvm) throws RemoteException { + public void detachVm(final RemoteVm rvm) throws RemoteException { rvm.detach(); } public int[] activeVms() throws MonitorException { - Object[] vms = null; - int[] vmids = null; - - vms = monitoredHost.activeVms().toArray(); - vmids = new int[vms.length]; + Object[] vms = this.monitoredHost.activeVms().toArray(); + int[] vmids = new int[vms.length]; for (int i = 0; i < vmids.length; i++) { - vmids[i] = ((Integer)vms[i]).intValue(); + vmids[i] = (Integer) vms[i]; } return vmids; } - public void vmStatusChanged(VmStatusChangeEvent ev) { + public void vmStatusChanged(final VmStatusChangeEvent ev) { synchronized(this.activeVms) { - activeVms.retainAll(ev.getActive()); + this.activeVms.retainAll(ev.getActive()); } } - public void disconnected(HostEvent ev) { + public void disconnected(final HostEvent ev) { // we only monitor the local host, so this event shouldn't occur. } } diff --git a/src/main/java/com/github/anthony_o/ejstatd/RemoteVmImpl.java b/src/main/java1.8/com/github/anthony_o/ejstatd/RemoteVmImpl.java similarity index 88% rename from src/main/java/com/github/anthony_o/ejstatd/RemoteVmImpl.java rename to src/main/java1.8/com/github/anthony_o/ejstatd/RemoteVmImpl.java index 7a5abae..7840b03 100644 --- a/src/main/java/com/github/anthony_o/ejstatd/RemoteVmImpl.java +++ b/src/main/java1.8/com/github/anthony_o/ejstatd/RemoteVmImpl.java @@ -41,25 +41,25 @@ */ public class RemoteVmImpl implements RemoteVm { - private BufferedMonitoredVm mvm; + private final BufferedMonitoredVm mvm; - RemoteVmImpl(BufferedMonitoredVm mvm) { + RemoteVmImpl(final BufferedMonitoredVm mvm) { this.mvm = mvm; } public byte[] getBytes() { - return mvm.getBytes(); + return this.mvm.getBytes(); } public int getCapacity() { - return mvm.getCapacity(); + return this.mvm.getCapacity(); } public void detach() { - mvm.detach(); + this.mvm.detach(); } public int getLocalVmId() { - return mvm.getVmIdentifier().getLocalVmId(); + return this.mvm.getVmIdentifier().getLocalVmId(); } } diff --git a/src/main/java11 b/src/main/java11 new file mode 120000 index 0000000..704cce5 --- /dev/null +++ b/src/main/java11 @@ -0,0 +1 @@ +java9 \ No newline at end of file diff --git a/src/main/java8 b/src/main/java8 new file mode 120000 index 0000000..fb30be1 --- /dev/null +++ b/src/main/java8 @@ -0,0 +1 @@ +java1.8 \ No newline at end of file diff --git a/src/main/java9/com/github/anthony_o/ejstatd/RemoteHostImpl.java b/src/main/java9/com/github/anthony_o/ejstatd/RemoteHostImpl.java new file mode 100644 index 0000000..74c339e --- /dev/null +++ b/src/main/java9/com/github/anthony_o/ejstatd/RemoteHostImpl.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.github.anthony_o.ejstatd; + +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.VmIdentifier; +import sun.jvmstat.monitor.event.HostEvent; +import sun.jvmstat.monitor.event.HostListener; +import sun.jvmstat.monitor.event.VmStatusChangeEvent; +import sun.jvmstat.monitor.BufferedMonitoredVm; +import sun.jvmstat.monitor.remote.RemoteHost; +import sun.jvmstat.monitor.remote.RemoteVm; + +import java.net.URISyntaxException; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; +import java.util.Set; + +/** + * Concrete implementation of the RemoteHost interface for the HotSpot + * PerfData rmi: protocol. + *

+ * This class provides remote access to the instrumentation exported + * by HotSpot Java Virtual Machines through the PerfData shared memory + * interface. + * + * @author Brian Doherty + * @since 1.5 + */ +public class RemoteHostImpl implements RemoteHost, HostListener { + + private MonitoredHost monitoredHost; + private final Set activeVms; + + public RemoteHostImpl() throws MonitorException { + try { + this.monitoredHost = MonitoredHost.getMonitoredHost("localhost"); + } catch (URISyntaxException e) { } + + this.activeVms = this.monitoredHost.activeVms(); + this.monitoredHost.addHostListener(this); + } + + public RemoteVm attachVm(final int lvmid, final String mode) throws RemoteException, MonitorException { + RemoteVm stub; + + final StringBuilder sb = new StringBuilder(); + sb.append("local://").append(lvmid).append("@localhost"); + if (mode != null) { + sb.append("?mode=").append(mode); + } + final String vmidStr = sb.toString(); + + try { + final VmIdentifier vmid = new VmIdentifier(vmidStr); + final MonitoredVm mvm = this.monitoredHost.getMonitoredVm(vmid); + final RemoteVmImpl rvm = new RemoteVmImpl((BufferedMonitoredVm)mvm); + stub = (RemoteVm) UnicastRemoteObject.exportObject(rvm, Integer.parseInt(System.getProperty("ejstatd.remoteVm.port", "0"))); + } + catch (final URISyntaxException e) { + throw new RuntimeException("Malformed VmIdentifier URI: " + vmidStr, e); + } + return stub; + } + + public void detachVm(final RemoteVm rvm) throws RemoteException { + rvm.detach(); + } + + public int[] activeVms() throws MonitorException { + Object[] vms = this.monitoredHost.activeVms().toArray(); + int[] vmids = new int[vms.length]; + + for (int i = 0; i < vmids.length; i++) { + vmids[i] = (Integer) vms[i]; + } + return vmids; + } + + public void vmStatusChanged(final VmStatusChangeEvent ev) { + synchronized(this.activeVms) { + this.activeVms.retainAll(ev.getActive()); + } + } + + public void disconnected(final HostEvent ev) { + // we only monitor the local host, so this event shouldn't occur. + } +} diff --git a/src/main/java9/com/github/anthony_o/ejstatd/RemoteVmImpl.java b/src/main/java9/com/github/anthony_o/ejstatd/RemoteVmImpl.java new file mode 100644 index 0000000..8191ef9 --- /dev/null +++ b/src/main/java9/com/github/anthony_o/ejstatd/RemoteVmImpl.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.github.anthony_o.ejstatd; + +import sun.jvmstat.monitor.BufferedMonitoredVm; +import sun.jvmstat.monitor.remote.RemoteVm; + +/** + * Concrete implementation of the RemoteVm interface for the HotSpot PerfData + * shared memory implementation of the jvmstat monitoring APIs. This class + * providing remote access to the instrumentation exported by a local HotSpot + * Java Virtual Machine. The instrumentation buffer is shipped in whole to + * the remote machine, which is responsible for parsing and provide access + * to the contained data. + * + * @author Brian Doherty + * @since 1.5 + */ +public class RemoteVmImpl implements RemoteVm { + + private final BufferedMonitoredVm mvm; + + RemoteVmImpl(final BufferedMonitoredVm mvm) { + this.mvm = mvm; + } + + public byte[] getBytes() { + return this.mvm.getBytes(); + } + + public int getCapacity() { + return this.mvm.getCapacity(); + } + + public void detach() { + this.mvm.detach(); + } + + public int getLocalVmId() { + return this.mvm.getVmIdentifier().getLocalVmId(); + } +}