/* * Copyright (c) 2013 Websquared, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * swsong - initial API and implementation */ package org.fastcatsearch.management; import java.io.File; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.OperatingSystemMXBean; import java.lang.management.RuntimeMXBean; import java.lang.reflect.Method; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SystemInfoHandler { private static Logger logger = LoggerFactory.getLogger(SystemInfoHandler.class); private static SystemInfoHandler instance = new SystemInfoHandler(); private File dummyFile = new File("."); public static SystemInfoHandler getInstance() { return instance; } private MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); private RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); private OperatingSystemMXBean osMXBean = ManagementFactory.getOperatingSystemMXBean(); private com.sun.management.OperatingSystemMXBean sunOsMXBean; private static int MEGABITE_UNIT = 1024 * 1024; private boolean isSunVmLowVersion; // sun jvm이면서 1.6이하인지 여부. 여기에 해당하면 // cpu사용률을 직접계산할 수 있다. private boolean isLoadAvgInfoSupported; // Load Average 지원여부. jvm vendor에 // 상관없이 1.6이상이면 표준MXBean에서 지원하는 // 스펙이다. private boolean isVmVersionHigh; // jvm버전이 1.7이상인지 여부. jvm cpu사용률과 system // cpu사용률을 표준MXBean에서 지원한다. private long sunNanoBefore; // cpu사용률을 직접계산할때 필요한 변수. Previous 시스템 시간 private long sunCpuBefore; // cpu사용률을 직접계산할때 필요한 변수. Previous cpu time. 나중에 // 이 값과 현재값과의 차이를 계산하여 cpu를 얼마나 사용했는지 계산하게됨. // 검색엔진 개발환경이 jvm1.5또는 1.6일때 1.6,1.7지원 메소드를 사용하면 컴파일이 안되며, 실제 운영환경에서도 // exception이 발생하므로 // java reflection method invocation을 사용한다. // JVM 1.7(21.0)에서만 지원하는 메서드 2개 private Method getSystemCpuLoadMethod; private Method getProcessCpuLoadMethod; // JVM 1.6(20.0)에서만 지워하는 메서드 private Method getSystemLoadAverageMethod; private boolean isWindows; private boolean isJvmCpuInfoSupported; private boolean isSystemCpuInfoSupported; private boolean isJvmMemoryInfoSupported = true; // 항상 지원. private int totalPhysicalMemorySize; // 시스템 전체메모리사이즈. public boolean isJvmCpuInfoSupported() { return isJvmCpuInfoSupported; } public boolean isSystemCpuInfoSupported() { return isSystemCpuInfoSupported; } public boolean isLoadAvgInfoSupported() { return isLoadAvgInfoSupported && !isWindows; } public boolean isJvmMemoryInfoSupported() { return isJvmMemoryInfoSupported; } public static void main(String[] args) throws InterruptedException { SystemInfoHandler h = SystemInfoHandler.getInstance(); logger.debug("isJvmCpuInfoSupported = " + h.isJvmCpuInfoSupported()); logger.debug("isSystemCpuInfoSupported = " + h.isSystemCpuInfoSupported()); logger.debug("isLoadAvgInfoSupported = " + h.isLoadAvgInfoSupported()); logger.debug("isJvmMemoryInfoSupported = " + h.isJvmMemoryInfoSupported()); logger.debug(""); JvmCpuInfo jvmCpuInfo = new JvmCpuInfo(); JvmMemoryInfo jvmMemoryInfo = new JvmMemoryInfo(); SystemDiskInfo systemDiskInfo = new SystemDiskInfo(); while (true) { h.checkJvmCpuInfo(jvmCpuInfo); h.checkJvmMemoryInfo(jvmMemoryInfo); h.checkSystemDiskInfo(systemDiskInfo); jvmCpuInfo.print(); jvmMemoryInfo.print(); systemDiskInfo.print(); Thread.sleep(1000); } } private SystemInfoHandler() { try { MEGABITE_UNIT = 1024 * 1024; String vmVendor = runtimeMXBean.getVmVendor(); String vmVersionStr = runtimeMXBean.getVmVersion(); isWindows = osMXBean.getName().startsWith("Windows"); Pattern pat = Pattern.compile("\\d*(\\.?\\d*)"); Matcher matcher = pat.matcher(vmVersionStr); if (matcher.find()) { vmVersionStr = matcher.group(); } float vmVersion = Float.parseFloat(vmVersionStr); logger.debug("VmVendor() = " + vmVendor); logger.debug("VmVersion() = " + vmVersionStr); // OperatingSystemMXBean은 벤더와 버전에 제약이 있다. // if ((vmVendor.startsWith("Oracle") || vmVendor.startsWith("Sun")) && // vmVersion < 21.0f) { if (vmVersion < 21.0f && ManagementFactory.getOperatingSystemMXBean() instanceof com.sun.management.OperatingSystemMXBean) { // sun MXBean에서는 getCpuTime을 제공하여 1.5과 1.6에서는 cpu사용률을 직접구현해야한다. isSunVmLowVersion = true; sunOsMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); initCpuForSunLowVersion(); isJvmCpuInfoSupported = true; // 1.7이상일 경우 표준 OperatingSystemMXBean을 사용한다. totalPhysicalMemorySize = (int) (sunOsMXBean.getTotalPhysicalMemorySize() / MEGABITE_UNIT); } // 1.7이상에서는 cpu사용률을 지원한다. // 1.6이상에서는 SystemLoadAverage를 지원한다. if (vmVersion >= 21.0f) { // jvm 1.7 isVmVersionHigh = true; isLoadAvgInfoSupported = true; prepareJvm17Method(); prepareJvm16Method(); } else if (vmVersion >= 20.0f) { isLoadAvgInfoSupported = true; // 1.6 method 생성 prepareJvm16Method(); } } catch (Throwable t) { logger.error("", t); } } private void prepareJvm17Method() { try { getSystemCpuLoadMethod = osMXBean.getClass().getMethod("getSystemCpuLoad"); getSystemCpuLoadMethod.setAccessible(true); logger.debug("OperatingSystemMXBean.getSystemCpuLoad() supported!"); isSystemCpuInfoSupported = true; } catch (Exception e) { logger.debug("OperatingSystemMXBean.getProcessCpuLoad() NOT supported!"); } try { getProcessCpuLoadMethod = osMXBean.getClass().getMethod("getProcessCpuLoad"); getProcessCpuLoadMethod.setAccessible(true); isJvmCpuInfoSupported = true; logger.debug("OperatingSystemMXBean.getProcessCpuLoad() supported!"); } catch (Exception e) { logger.debug("OperatingSystemMXBean.getProcessCpuLoad() NOT supported!"); } } private void prepareJvm16Method() { try { getSystemLoadAverageMethod = osMXBean.getClass().getMethod("getSystemLoadAverage"); getSystemLoadAverageMethod.setAccessible(true); isLoadAvgInfoSupported = true; logger.debug("OperatingSystemMXBean.getSystemLoadAverage() supported!"); } catch (Exception e) { logger.debug("OperatingSystemMXBean.getSystemLoadAverage() NOT supported!"); } } public void checkJvmMemoryInfo(JvmMemoryInfo jvmMemoryInfo) { jvmMemoryInfo.init((int) (memoryMXBean.getHeapMemoryUsage().getMax() / MEGABITE_UNIT), (int) (memoryMXBean.getHeapMemoryUsage().getCommitted() / MEGABITE_UNIT), (int) (memoryMXBean.getHeapMemoryUsage().getUsed() / MEGABITE_UNIT), (int) (memoryMXBean.getNonHeapMemoryUsage().getMax() / MEGABITE_UNIT), (int) (memoryMXBean .getNonHeapMemoryUsage().getCommitted() / MEGABITE_UNIT), (int) (memoryMXBean.getNonHeapMemoryUsage().getUsed() / MEGABITE_UNIT), totalPhysicalMemorySize); } public void checkJvmCpuInfo(JvmCpuInfo jvmCpuInfo) { /* * 1. cpu사용률 생성 */ if (isVmVersionHigh) { // 표준 mxbean사용. try { // getSystemCpuLoadMethod.setAccessible(true); // getProcessCpuLoadMethod.setAccessible(true); double cpuLoad = (Double) (getSystemCpuLoadMethod.invoke(osMXBean)); double jvmLoad = (Double) (getProcessCpuLoadMethod.invoke(osMXBean)); jvmCpuInfo.systemCpuUse = (int) (cpuLoad * 100); jvmCpuInfo.jvmCpuUse = (int) (jvmLoad * 100); } catch (Exception e) { jvmCpuInfo.systemCpuUse = 0; jvmCpuInfo.jvmCpuUse = 0; e.printStackTrace(); } } else if (isSunVmLowVersion) { // 커스텀 cpu 사용률 생성. checkCpuForSunLowVersion(jvmCpuInfo); } else { // 지원안함. jvmCpuInfo.systemCpuUse = 0; jvmCpuInfo.jvmCpuUse = 0; } /* * 2. LoadAvg 생성 LoadAvg는 벤더에 독립적이며 1.6이상 버전에만 의존한다. */ if (isLoadAvgInfoSupported) { // 로드AVG생성 try { double loadAvg = (Double) (getSystemLoadAverageMethod.invoke(osMXBean)); // logger.debug("osMXBean = "+osMXBean.getSystemLoadAverage()); jvmCpuInfo.systemLoadAverage = loadAvg; } catch (Exception e) { jvmCpuInfo.systemLoadAverage = 0.0; } } else { // clear jvmCpuInfo.systemLoadAverage = 0.0; } } public void checkSystemDiskInfo(SystemDiskInfo systemDiskInfo) { systemDiskInfo.totalDiskSize = (int) (dummyFile.getTotalSpace() / MEGABITE_UNIT); systemDiskInfo.freeDiskSize = (int) (dummyFile.getFreeSpace() / MEGABITE_UNIT); systemDiskInfo.usedDiskSize = systemDiskInfo.totalDiskSize - systemDiskInfo.freeDiskSize; } private void initCpuForSunLowVersion() { sunNanoBefore = System.nanoTime(); sunCpuBefore = sunOsMXBean.getProcessCpuTime(); } private void checkCpuForSunLowVersion(JvmCpuInfo jvmCpuInfo) { long sunCpuAfter = sunOsMXBean.getProcessCpuTime(); long sunNanoAfter = System.nanoTime(); int percent; if (sunNanoAfter > sunNanoBefore) { percent = (int) (((sunCpuAfter - sunCpuBefore) * 100L) / (sunNanoAfter - sunNanoBefore)); } else { percent = 0; } // logger.debug("Cpu usage: "+percent+"%"+", "+(sunCpuAfter-sunCpuBefore)+" / "+(sunNanoAfter-sunNanoBefore)); sunNanoBefore = System.nanoTime(); sunCpuBefore = sunOsMXBean.getProcessCpuTime(); jvmCpuInfo.systemCpuUse = 0; jvmCpuInfo.jvmCpuUse = percent; } }