From f96457a0aced987852892a5b6862ebfdaad273b4 Mon Sep 17 00:00:00 2001 From: myxyx999 <2110276090@email.szu.edu.cn> Date: Thu, 29 Sep 2022 09:48:11 +0800 Subject: [PATCH] refactor: JvmProbe --- config/gala-gopher.conf | 4 +- src/probes/extends/java.probe/build.sh | 101 +++++++--- src/probes/extends/java.probe/install.sh | 15 +- .../extends/java.probe/jvm.probe/Vm.java | 68 ------- .../jvm.probe/config/META-INF/MANIFEST.MF | 5 + .../java.probe/jvm.probe/jvm_probe.meta | 71 +++++-- .../jvm.probe/{ => src}/JvmProbe.java | 79 ++++---- .../extends/java.probe/jvm.probe/src/Vm.java | 182 ++++++++++++++++++ 8 files changed, 368 insertions(+), 157 deletions(-) delete mode 100755 src/probes/extends/java.probe/jvm.probe/Vm.java create mode 100644 src/probes/extends/java.probe/jvm.probe/config/META-INF/MANIFEST.MF rename src/probes/extends/java.probe/jvm.probe/{ => src}/JvmProbe.java (52%) create mode 100644 src/probes/extends/java.probe/jvm.probe/src/Vm.java diff --git a/config/gala-gopher.conf b/config/gala-gopher.conf index 13a110b4..59f840b2 100644 --- a/config/gala-gopher.conf +++ b/config/gala-gopher.conf @@ -199,9 +199,9 @@ extend_probes = }, { name = "jvmprobe"; - command = "java -classpath $JAVA_HOME/lib/tools.jar:/opt/gala-gopher/extend_probes/ JvmProbe" + command = "java -jar /opt/gala-gopher/extend_probes/JvmProbe.jar" param = "-t 5"; - start_check = "[ $JAVA_HOME ] && [ -e $JAVA_HOME/lib/tools.jar ] && echo 1"; + start_check = "[ -z $(which java 2>/dev/null) ] && echo 0 || echo 1"; check_type = "count"; switch = "auto"; } diff --git a/src/probes/extends/java.probe/build.sh b/src/probes/extends/java.probe/build.sh index f54852ae..eddee70a 100755 --- a/src/probes/extends/java.probe/build.sh +++ b/src/probes/extends/java.probe/build.sh @@ -4,37 +4,94 @@ PRJ_DIR=$(dirname $(readlink -f "$0")) BUILD_FILES=${PRJ_DIR}/jvm.probe cd ${BUILD_FILES} +function find_jars() +{ + if [ -z $JAVA_HOME ]; + then + # find jdk + clink_path=$(echo $(ls -lrt $javac_link) | awk -F " " '{print $NF}' ) + link_path=$(echo $(ls -lrt $link_path) | awk -F " " '{print $NF}' ) + jdk_path=$(dirname $(dirname $link_path)) + dir=$jdk_path + else + dir=$JAVA_HOME + fi + + #tools.jar + if [ -e $dir/lib/tools.jar ]; + then + mkdir -p lib + cp $dir/lib/tools.jar lib/ + else + echo "Error: tools.jar not found" + return 1 + fi + + #management.jar + if [ -e $dir/jre/lib/management-agent.jar ]; + then + cp $dir/jre/lib/management-agent.jar lib/ + else + echo "Error: management-agent.jar not found" + return 1 + fi + + return 0 +} + +function make_probe_jar() +{ + mkdir -p tmp + cd tmp + javac -cp ../lib/tools.jar ../src/*.java -d ./ + + if [ -z $(which jar 2>/dev/null) ]; + then + echo "Error: jar command not found" + return 1 + else + jar xf ../lib/tools.jar #>/dev/null 2>&1 + cp ../lib/management-agent.jar ./ + cd .. + jar cfm JvmProbe.jar config/META-INF/MANIFEST.MF -C tmp/ . #2>/dev/null + fi + + rm -rf tmp 2>/dev/null +} + +function compile_clean() +{ + rm -rf lib 2>/dev/null + rm -rf tmp 2>/dev/null +} + if [ "$1" == "-c" -o "$1" == "--clean" ]; then - rm -rf *.class + compile_clean exit fi java_link=$(which java 2>/dev/null) javac_link=$(which javac 2>/dev/null) -if [ -z $java_link ] && [ -z $javac_link ]; +if [ -z $java_link ] || [ -z $javac_link ]; then - echo "java and javac : command not found" - exit 1 -else - if [ -z $JAVA_HOME ]; + echo "Error: java and javac : command not found" + return 1 +else + find_jars + if [ $? -eq 1 ]; then - # find jdk - link_path=$(echo $(ls -lrt $javac_link) | awk -F " " '{print $NF}' ) - link_path=$(echo $(ls -lrt $link_path) | awk -F " " '{print $NF}' ) - jdk_path=$(dirname $(dirname $link_path)) - dir=$jdk_path/lib - else - dir=$JAVA_HOME/lib - fi - - #tools.jar - if [ -e $dir/tools.jar ]; + exit 1 + fi + + make_probe_jar + if [ $? -eq 1 ]; then - javac -cp $dir/tools.jar JvmProbe.java Vm.java - else - echo "tools.jar not found" - exit 1 - fi + exit 1 + fi + + compile_clean + exit fi + diff --git a/src/probes/extends/java.probe/install.sh b/src/probes/extends/java.probe/install.sh index fe0392b2..d58ffe4a 100755 --- a/src/probes/extends/java.probe/install.sh +++ b/src/probes/extends/java.probe/install.sh @@ -2,13 +2,10 @@ PROGRAM=$0 PRJ_DIR=$(dirname $(readlink -f "$0")) INSTALL_FILES=${PRJ_DIR}/jvm.probe +cd ${INSTALL_FILES} + + if [ $# -eq 1 ]; then + \cp JvmProbe.jar $1 + fi + -if [ $# -eq 1 ]; then - cd ${INSTALL_FILES} - for file in ${INSTALL_FILES}/*; do - if [ "${file##*.}" = "class" ]; - then - \cp ${file} $1 - fi - done -fi diff --git a/src/probes/extends/java.probe/jvm.probe/Vm.java b/src/probes/extends/java.probe/jvm.probe/Vm.java deleted file mode 100755 index d35bb7ca..00000000 --- a/src/probes/extends/java.probe/jvm.probe/Vm.java +++ /dev/null @@ -1,68 +0,0 @@ -import com.sun.tools.attach.*; -import javax.management.MBeanServerConnection; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; - -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.lang.management.ThreadMXBean; - - -public class Vm { - - private VirtualMachineDescriptor virtualMachineDescriptor; - private MBeanServerConnection mBeanServerConnection; - private JMXConnector connector; - private String canonicalPath; - - final String jmxRemote = "com.sun.management.jmxremote"; - final String localConnectorAddress = "com.sun.management.jmxremote" + ".localConnectorAddress"; - - public Vm(VirtualMachineDescriptor virtualMachineDescriptor,String canonicalPath) throws AgentLoadException, IOException, AttachNotSupportedException, AgentInitializationException { - this.virtualMachineDescriptor = virtualMachineDescriptor; - this.canonicalPath = canonicalPath; - this.mBeanServerConnection = getTargetVmConnection(virtualMachineDescriptor.id()); - } - - public MBeanServerConnection getTargetVmConnection(String vmId) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException { - // attach - VirtualMachine virtualMachine = VirtualMachine.attach(vmId); - virtualMachine.loadAgent(canonicalPath, jmxRemote); - String connectorAddress = (String) virtualMachine.getAgentProperties().get(localConnectorAddress); - virtualMachine.detach(); - - connector = JMXConnectorFactory.connect(new JMXServiceURL(connectorAddress)); - MBeanServerConnection mBeanServerConnection = connector.getMBeanServerConnection(); - return mBeanServerConnection; - } - - public void getData() throws IOException { - getInfo(this.mBeanServerConnection); - connector.close(); - } - - public void getInfo(MBeanServerConnection connection) throws IOException { - String jvmPid = virtualMachineDescriptor.id(); - String[] split = virtualMachineDescriptor.displayName().split(" "); - String pkgNameMainClass = split[0]; - RuntimeMXBean runtimeMXBean = ManagementFactory.newPlatformMXBeanProxy( - connection, ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class); - String jvmVersion = runtimeMXBean.getSpecVersion(); - String jvmType = runtimeMXBean.getVmName(); - Long processStartTimeSeconds = runtimeMXBean.getStartTime(); - Long processCpuSecondsTotal = runtimeMXBean.getUptime(); - - ThreadMXBean threadMXBean = ManagementFactory.newPlatformMXBeanProxy( - connection, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class); - int threadsCurrent = threadMXBean.getThreadCount(); - int threadsPeak = threadMXBean.getPeakThreadCount(); - int threadsDeadlocked = 0; - if (threadMXBean.findDeadlockedThreads() != null) { - threadsDeadlocked = threadMXBean.findDeadlockedThreads().length; - } - System.out.printf("|jvm|%s|%s|%s|%s|%d|%d|%d|%d|%d|\n", jvmPid,pkgNameMainClass, jvmVersion, jvmType - , processStartTimeSeconds, processCpuSecondsTotal, threadsCurrent,threadsPeak, threadsDeadlocked); - } -} diff --git a/src/probes/extends/java.probe/jvm.probe/config/META-INF/MANIFEST.MF b/src/probes/extends/java.probe/jvm.probe/config/META-INF/MANIFEST.MF new file mode 100644 index 00000000..9f2a9af4 --- /dev/null +++ b/src/probes/extends/java.probe/jvm.probe/config/META-INF/MANIFEST.MF @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +Class-Path: management-agent.jar +Created-By: 1.8.0_333 (Oracle Corporation) +Main-Class: JvmProbe + diff --git a/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta b/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta index c8092483..816d2fc9 100755 --- a/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta +++ b/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta @@ -7,7 +7,7 @@ measurements: entity_name: "jvm", fields: ( - { + { description: "ID of current java process ", type: "key", name: "tgid", @@ -18,14 +18,14 @@ measurements: name: "pkg_name_main_class", }, { - description: "Specification Version of JVM ", + description: "JVM specification version ", type: "label", - name: "version", + name: "jvm_version", }, - { - description: "Type of JVM ", + { + description: "JVM implementation name ", type: "label", - name: "type", + name: "jvm_type", }, { description: "Process start time in seconds", @@ -33,17 +33,17 @@ measurements: name: "process_start_time_seconds", }, { - description: "Process total time in seconds", + description: "Process run time in seconds", type: "gauge", - name: "process_cpu_seconds_total", + name: "process_run_time_seconds", }, { - description: "The number of threads in the current java process", - type: "gauge", - name: "threads_current", + description: "The number of threads in the current process", + type: "gauge", + name: "threads_current", }, { - description: "The peak number of threads of the java process", + description: "The peak number of threads of the java process", type: "gauge", name: "threads_peak", }, @@ -51,7 +51,52 @@ measurements: description: "Deadlocked JVM thread number", type: "gauge", name: "threads_deadlocked", - }, + }, + { + description: "Used bytes of JVM _Heap memory area", + type: "gauge", + name: "heap_memory_bytes_used", + }, + { + description: "JVM _Heap occupation", + type: "gauge", + name: "heap_occuped_percent", + }, + { + description: "Used bytes of JVM _NonHeap memory area", + type: "gauge", + name: "nonheap_memory_bytes_used", + }, + { + description: "JVM _NonHeap occupation", + type: "gauge", + name: "nonheap_occuped_percent", + }, + { + description: "Garbage collector collection counts", + type: "gauge", + name: "gc_total_count", + }, + { + description: "Total garbage collector collection time", + type: "gauge", + name: "gc_total_seconds", + }, + { + description: "The total capacity of the JVM buffer pools", + type: "gauge", + name: "buffer_pool_total_size", + }, + { + description: "the memory that the JVM uses for buffer pools", + type: "gauge", + name: "buffer_pool_used_bytes", + }, + { + description: "Garbage collectors` average usage", + type: "gauge", + name: "gc_activity_util", + }, ) } ) diff --git a/src/probes/extends/java.probe/jvm.probe/JvmProbe.java b/src/probes/extends/java.probe/jvm.probe/src/JvmProbe.java similarity index 52% rename from src/probes/extends/java.probe/jvm.probe/JvmProbe.java rename to src/probes/extends/java.probe/jvm.probe/src/JvmProbe.java index fc9e4504..b8a8d03b 100644 --- a/src/probes/extends/java.probe/jvm.probe/JvmProbe.java +++ b/src/probes/extends/java.probe/jvm.probe/src/JvmProbe.java @@ -1,7 +1,9 @@ import com.sun.tools.attach.*; - import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; import java.util.List; import java.util.HashMap; import java.util.concurrent.ExecutorService; @@ -12,15 +14,20 @@ public class JvmProbe { public static List virtualMachineDescriptors; public static ExecutorService executorService; - public static int time =5 ; - public static String canonicalPath; + public static int time = 5; + public static String agentPath; + + final static String agent = "management-agent.jar"; public static void main(String[] args) { - // set args ArgsParse(args); - //get canonicalPath - GetFileCanonicalPath(); - //run probe + try { + agentPath = getTemporaryRes(agent); + } catch (IOException e) { + System.out.println(e.getMessage()); + System.exit(1); + } + while (true) { try { probe(); @@ -29,34 +36,7 @@ public class JvmProbe { System.out.println(e.getMessage()); System.exit(1); } - } - } - - public static void GetFileCanonicalPath() { - String existAgentPath2 = File.separator + "lib" + File.separator + "management-agent.jar"; - String existAgentPath1 = File.separator + "jre" + existAgentPath2; - String javaHome = System.getProperties().getProperty("java.home"); - String agentPath = javaHome + existAgentPath1; - - File file = new File(agentPath); - if (!file.exists()) { - agentPath = javaHome + existAgentPath2; - file = new File(agentPath); - if (!file.exists()) { - try { - throw new IOException("[JVM Probe] management-agent.jar not found"); - } catch (IOException e) { - System.out.println(e.getMessage()); - System.exit(1); - } - } - } - try { - canonicalPath = file.getCanonicalPath(); - } catch (IOException e) { - System.out.println(e.getMessage()); - System.exit(1); } } @@ -77,19 +57,32 @@ public class JvmProbe { if (executorService == null) { executorService = Executors.newFixedThreadPool(5); } + for (VirtualMachineDescriptor virtualMachineDescriptor : virtualMachineDescriptors) { - executorService.submit(new Runnable() { - @Override - public void run() { - try { - Vm vm = new Vm(virtualMachineDescriptor,canonicalPath); - vm.getData(); - } catch (AgentLoadException | IOException | AttachNotSupportedException | AgentInitializationException e) { - System.out.println(e.getMessage()); - } + executorService.submit(() -> { + try { + Vm vm = new Vm(virtualMachineDescriptor, agentPath); + vm.getData(); + } catch (IOException | AgentLoadException | AttachNotSupportedException | AgentInitializationException | InterruptedException e) { + System.out.println(e.getMessage()); } }); } } + public static String getTemporaryRes(String resource) throws IOException { + //read embedded resource from this JAR + InputStream inputStream = JvmProbe.class.getResourceAsStream(resource); + if(inputStream == null){ + throw new IOException("Resource not found in the JAR"); + } + + // create a temporary file + File temporaryFile = File.createTempFile("resource", null); + temporaryFile.deleteOnExit(); + + // Copy the resource data into the temporary file + Files.copy(inputStream, temporaryFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + return temporaryFile.getAbsolutePath(); + } } diff --git a/src/probes/extends/java.probe/jvm.probe/src/Vm.java b/src/probes/extends/java.probe/jvm.probe/src/Vm.java new file mode 100644 index 00000000..9971167a --- /dev/null +++ b/src/probes/extends/java.probe/jvm.probe/src/Vm.java @@ -0,0 +1,182 @@ +import com.sun.tools.attach.*; +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import java.io.IOException; +import java.lang.management.*; +import java.util.List; +import java.util.concurrent.TimeUnit; + + +public class Vm { + public VirtualMachineDescriptor virtualMachineDescriptor; + public MBeanServerConnection mBeanServerConnection; + public JMXConnector connector; + public final String canonicalPath; + public StringBuilder res; + + final String localConnectorAddress = "com.sun.management.jmxremote.localConnectorAddress"; + + public Vm(VirtualMachineDescriptor virtualMachineDescriptor,String canonicalPath) throws AgentLoadException, IOException, AttachNotSupportedException, AgentInitializationException { + this.virtualMachineDescriptor = virtualMachineDescriptor; + this.canonicalPath = canonicalPath; + getTargetVmConnection(virtualMachineDescriptor.id()); + res = new StringBuilder(); + } + + private void getTargetVmConnection(String vmId) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException { + + VirtualMachine virtualMachine = VirtualMachine.attach(vmId); + virtualMachine.loadAgent(canonicalPath); + + String connectorAddress = (String) virtualMachine.getAgentProperties().get(localConnectorAddress); + virtualMachine.detach(); + this.connector = JMXConnectorFactory.connect(new JMXServiceURL(connectorAddress)); + this.mBeanServerConnection = connector.getMBeanServerConnection(); + } + + public void getData() throws IOException, InterruptedException { + try { + getInfo(this.mBeanServerConnection); + } catch (IOException e) { + System.out.println(e.getMessage()); + } finally { + try { + connector.close(); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + } + + private void getInfo(MBeanServerConnection connection) throws IOException, InterruptedException { + RuntimeMXBean runtimeMXBean = ManagementFactory.newPlatformMXBeanProxy( + connection, ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class); + com.sun.management.OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.newPlatformMXBeanProxy(connection, + ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, com.sun.management.OperatingSystemMXBean.class); + List garbageCollectorMXBeans = ManagementFactory.getPlatformMXBeans( + connection,GarbageCollectorMXBean.class); + ThreadMXBean threadMXBean = ManagementFactory.newPlatformMXBeanProxy( + connection, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class); + MemoryMXBean memoryMXBean = ManagementFactory.newPlatformMXBeanProxy( + connection, ManagementFactory.MEMORY_MXBEAN_NAME, MemoryMXBean.class); + List pools = ManagementFactory.getPlatformMXBeans( + connection,BufferPoolMXBean.class); + // tid % mainclass + String jvmPid = virtualMachineDescriptor.id(); + String[] split = virtualMachineDescriptor.displayName().split(" "); + String pkgNameMainClass = split[0]; + res.append(String.format("|jvm|%s|%s|", jvmPid, pkgNameMainClass)); + + // vesion % type + String jvmVersion = runtimeMXBean.getSpecVersion(); + String jvmType = runtimeMXBean.getVmName(); + res.append(String.format("%s|%s|", jvmVersion, jvmType)); + + // gc + double gcDetail = getGarbageCollectionUsage(runtimeMXBean, operatingSystemMXBean, garbageCollectorMXBeans); + long gc_counts = getTotalGarbageCollectionCount(garbageCollectorMXBeans); + long gc_time_ms = getTotalGarbageCollectionTime(garbageCollectorMXBeans); + res.append(String.format("%.2f|%d|%d|", gcDetail, gc_counts, gc_time_ms)); + // process & thread + Long processStartTimeSeconds = runtimeMXBean.getStartTime(); + Long processCpuSecondsTotal = runtimeMXBean.getUptime(); + + int threadsCurrent = threadMXBean.getThreadCount(); + int threadsPeak = threadMXBean.getPeakThreadCount(); + int threadsDeadlocked = 0; + if(threadMXBean.findDeadlockedThreads() != null) { + threadsDeadlocked = threadMXBean.findDeadlockedThreads().length; + } + + res.append(String.format("%d|%d|%d|%d|%d|", processStartTimeSeconds, processCpuSecondsTotal, threadsCurrent, threadsPeak, threadsDeadlocked)); + + // heap + double heap_occupied = 100.0 * Double.valueOf(memoryMXBean.getHeapMemoryUsage().getCommitted()) / memoryMXBean.getHeapMemoryUsage().getMax(); + long heap_used = memoryMXBean.getHeapMemoryUsage().getUsed(); + res.append(String.format("%d|%.2f|", heap_used, heap_occupied)); + + // noheap + long noheap_used = memoryMXBean.getNonHeapMemoryUsage().getUsed(); + double noheap_occupied = memoryMXBean.getNonHeapMemoryUsage().getMax(); + if(noheap_occupied > 0) { + noheap_occupied = 100.0 * Double.valueOf(memoryMXBean.getNonHeapMemoryUsage().getCommitted()) / noheap_occupied; + res.append(String.format("%d|%.2f|", noheap_used, noheap_occupied)); + } + else { + res.append(String.format("%d|%.0f|", noheap_used,noheap_occupied)); + } + // bufferpool + long bf_capacity = getTotalBufferPoolsCapacity(pools); + long bf_used = getTotalBufferPoolsUsed(pools); + res.append(String.format("%d|%d|\n", bf_capacity, bf_used)); + System.out.printf(res.toString()); + } + + private long getTotalGarbageCollectionCount(List garbageCollectorMXBeans) { + long gc_count=0; + for(GarbageCollectorMXBean gc :garbageCollectorMXBeans) { + gc_count +=gc.getCollectionCount(); + } + return gc_count; + } + + private long getTotalGarbageCollectionTime(List gcmList) { + long total_ms=0; + for(GarbageCollectorMXBean gc :gcmList) { + total_ms += gc.getCollectionTime(); + } + return total_ms; + } + + private double getGarbageCollectionUsage(RuntimeMXBean runtime, com.sun.management.OperatingSystemMXBean os, List gcmList) { + // 上一个cpu运行记录时间点 + long prevUpTime = runtime.getUptime(); + // 当时cpu运行时间 + long upTime; + // 上一次cpu运行总时间 + long prevProcessCpuTime = os.getProcessCpuTime(); + // 当前cpu运行总时间 + long processCpuTime; + // 上一次gc运行总时间 + long prevProcessGcTime = getTotalGarbageCollectionTime(gcmList); + // 当前gc运行总时间 + long processGcTime; + // 可用内核数量 + int processorCount =os.getAvailableProcessors(); + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + System.exit(1); + } + processCpuTime = os.getProcessCpuTime(); + processGcTime = getTotalGarbageCollectionTime(gcmList); + upTime = runtime.getUptime(); + long upTimeDiff = upTime - prevUpTime; + //processGcTimeDiff 取到得是纳秒数 1ms = 1000000ns + //计算gccpu使用率 + long processGcTimeDiff = processGcTime - prevProcessGcTime; + double gcDetail = (processGcTimeDiff * 100.0 /1000000/ processorCount / upTimeDiff); + return gcDetail; + } + + private long getTotalBufferPoolsCapacity(List bufferpools) { + long total_bytes = 0; + for (BufferPoolMXBean bpool : bufferpools) { + total_bytes += bpool.getTotalCapacity(); + } + return total_bytes; + } + + private long getTotalBufferPoolsUsed(List bufferpools) { + long total_bytes = 0; + for (BufferPoolMXBean bpool : bufferpools) { + total_bytes += bpool.getMemoryUsed(); + } + return total_bytes; + } + +} + -- Gitee