/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// XXX TODO: Source code line length
// XXX TODO: More JavaDoc
// XXX Optional: Add support for com.sun.management specific mbean
//               (http://docs.oracle.com/javase/7/docs/jre/api/management/extension/index.html)
// XXX Optional: Wire additional public static methods implemented here
//               to the manager (think about manager access roles!)
//                 setLoggerLevel(),
//                 setVerboseClassLoading(),
//                 setThreadContentionMonitoringEnabled(),
//                 setThreadCpuTimeEnabled(),
//                 resetPeakThreadCount(),
//                 setVerboseGarbageCollection()
//                 gc(),
//                 resetPeakUsage(),
//                 setUsageThreshold(),
//                 setCollectionUsageThreshold()

package org.apache.tomcat.util;

import java.lang.management.ClassLoadingMXBean;
import java.lang.management.CompilationMXBean;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryManagerMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.MonitorInfo;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.PlatformLoggingMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.res.StringManager;

public class Diagnostics {

    private static final String PACKAGE = "org.apache.tomcat.util";
    private static final StringManager sm = StringManager.getManager(PACKAGE);

    private static final String INDENT1 = "  ";
    private static final String INDENT2 = "\t";
    private static final String INDENT3 = "   ";
    private static final String CRLF = "\r\n";
    private static final String vminfoSystemProperty = "java.vm.info";

    private static final Log log = LogFactory.getLog(Diagnostics.class);

    private static final SimpleDateFormat timeformat =
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    /* Some platform MBeans */
    private static final ClassLoadingMXBean classLoadingMXBean =
        ManagementFactory.getClassLoadingMXBean();
    private static final CompilationMXBean compilationMXBean =
        ManagementFactory.getCompilationMXBean();
    private static final OperatingSystemMXBean operatingSystemMXBean =
        ManagementFactory.getOperatingSystemMXBean();
    private static final RuntimeMXBean runtimeMXBean =
        ManagementFactory.getRuntimeMXBean();
    private static final ThreadMXBean threadMXBean =
        ManagementFactory.getThreadMXBean();

    // XXX Not sure whether the following MBeans should better
    // be retrieved on demand, i.e. whether they can change
    // dynamically in the MBeanServer.
    private static final PlatformLoggingMXBean loggingMXBean =
        ManagementFactory.getPlatformMXBean(PlatformLoggingMXBean.class);
    private static final MemoryMXBean memoryMXBean =
        ManagementFactory.getMemoryMXBean();
    private static final List<GarbageCollectorMXBean> garbageCollectorMXBeans =
        ManagementFactory.getGarbageCollectorMXBeans();
    private static final List<MemoryManagerMXBean> memoryManagerMXBeans =
        ManagementFactory.getMemoryManagerMXBeans();
    private static final List<MemoryPoolMXBean> memoryPoolMXBeans =
        ManagementFactory.getMemoryPoolMXBeans();

    
Check whether thread contention monitoring is enabled.
Returns:true if thread contention monitoring is enabled
/** * Check whether thread contention monitoring is enabled. * * @return true if thread contention monitoring is enabled */
public static boolean isThreadContentionMonitoringEnabled() { return threadMXBean.isThreadContentionMonitoringEnabled(); }
Enable or disable thread contention monitoring via the ThreadMxMXBean.
Params:
  • enable – whether to enable thread contention monitoring
/** * Enable or disable thread contention monitoring via the ThreadMxMXBean. * * @param enable whether to enable thread contention monitoring */
public static void setThreadContentionMonitoringEnabled(boolean enable) { threadMXBean.setThreadContentionMonitoringEnabled(enable); boolean checkValue = threadMXBean.isThreadContentionMonitoringEnabled(); if (enable != checkValue) { log.error("Could not set threadContentionMonitoringEnabled to " + enable + ", got " + checkValue + " instead"); } }
Check whether thread cpu time measurement is enabled.
Returns:true if thread cpu time measurement is enabled
/** * Check whether thread cpu time measurement is enabled. * * @return true if thread cpu time measurement is enabled */
public static boolean isThreadCpuTimeEnabled() { return threadMXBean.isThreadCpuTimeEnabled(); }
Enable or disable thread cpu time measurement via the ThreadMxMXBean.
Params:
  • enable – whether to enable thread cpu time measurement
/** * Enable or disable thread cpu time measurement via the ThreadMxMXBean. * * @param enable whether to enable thread cpu time measurement */
public static void setThreadCpuTimeEnabled(boolean enable) { threadMXBean.setThreadCpuTimeEnabled(enable); boolean checkValue = threadMXBean.isThreadCpuTimeEnabled(); if (enable != checkValue) { log.error("Could not set threadCpuTimeEnabled to " + enable + ", got " + checkValue + " instead"); } }
Reset peak thread count in ThreadMXBean
/** * Reset peak thread count in ThreadMXBean */
public static void resetPeakThreadCount() { threadMXBean.resetPeakThreadCount(); }
Set verbose class loading
Params:
  • verbose – whether to enable verbose class loading
/** * Set verbose class loading * * @param verbose whether to enable verbose class loading */
public static void setVerboseClassLoading(boolean verbose) { classLoadingMXBean.setVerbose(verbose); boolean checkValue = classLoadingMXBean.isVerbose(); if (verbose != checkValue) { log.error("Could not set verbose class loading to " + verbose + ", got " + checkValue + " instead"); } }
Set logger level
Params:
  • loggerName – the name of the logger
  • levelName – the level to set
/** * Set logger level * * @param loggerName the name of the logger * @param levelName the level to set */
public static void setLoggerLevel(String loggerName, String levelName) { loggingMXBean.setLoggerLevel(loggerName, levelName); String checkValue = loggingMXBean.getLoggerLevel(loggerName); if (!checkValue.equals(levelName)) { log.error("Could not set logger level for logger '" + loggerName + "' to '" + levelName + "', got '" + checkValue + "' instead"); } }
Set verbose garbage collection logging
Params:
  • verbose – whether to enable verbose gc logging
/** * Set verbose garbage collection logging * * @param verbose whether to enable verbose gc logging */
public static void setVerboseGarbageCollection(boolean verbose) { memoryMXBean.setVerbose(verbose); boolean checkValue = memoryMXBean.isVerbose(); if (verbose != checkValue) { log.error("Could not set verbose garbage collection logging to " + verbose + ", got " + checkValue + " instead"); } }
Initiate garbage collection via MX Bean
/** * Initiate garbage collection via MX Bean */
public static void gc() { memoryMXBean.gc(); }
Reset peak memory usage data in MemoryPoolMXBean
Params:
  • name – name of the MemoryPoolMXBean or "all"
/** * Reset peak memory usage data in MemoryPoolMXBean * * @param name name of the MemoryPoolMXBean or "all" */
public static void resetPeakUsage(String name) { for (MemoryPoolMXBean mbean: memoryPoolMXBeans) { if (name.equals("all") || name.equals(mbean.getName())) { mbean.resetPeakUsage(); } } }
Set usage threshold in MemoryPoolMXBean
Params:
  • name – name of the MemoryPoolMXBean
  • threshold – the threshold to set
Returns:true if setting the threshold succeeded
/** * Set usage threshold in MemoryPoolMXBean * * @param name name of the MemoryPoolMXBean * @param threshold the threshold to set * @return true if setting the threshold succeeded */
public static boolean setUsageThreshold(String name, long threshold) { for (MemoryPoolMXBean mbean: memoryPoolMXBeans) { if (name.equals(mbean.getName())) { try { mbean.setUsageThreshold(threshold); return true; } catch (IllegalArgumentException ex) { // IGNORE } catch (UnsupportedOperationException ex) { // IGNORE } return false; } } return false; }
Set collection usage threshold in MemoryPoolMXBean
Params:
  • name – name of the MemoryPoolMXBean
  • threshold – the collection threshold to set
Returns:true if setting the threshold succeeded
/** * Set collection usage threshold in MemoryPoolMXBean * * @param name name of the MemoryPoolMXBean * @param threshold the collection threshold to set * @return true if setting the threshold succeeded */
public static boolean setCollectionUsageThreshold(String name, long threshold) { for (MemoryPoolMXBean mbean: memoryPoolMXBeans) { if (name.equals(mbean.getName())) { try { mbean.setCollectionUsageThreshold(threshold); return true; } catch (IllegalArgumentException ex) { // IGNORE } catch (UnsupportedOperationException ex) { // IGNORE } return false; } } return false; }
Formats the thread dump header for one thread.
Params:
  • ti – the ThreadInfo describing the thread
Returns:the formatted thread dump header
/** * Formats the thread dump header for one thread. * * @param ti the ThreadInfo describing the thread * @return the formatted thread dump header */
private static String getThreadDumpHeader(ThreadInfo ti) { StringBuilder sb = new StringBuilder("\"" + ti.getThreadName() + "\""); sb.append(" Id=" + ti.getThreadId()); sb.append(" cpu=" + threadMXBean.getThreadCpuTime(ti.getThreadId()) + " ns"); sb.append(" usr=" + threadMXBean.getThreadUserTime(ti.getThreadId()) + " ns"); sb.append(" blocked " + ti.getBlockedCount() + " for " + ti.getBlockedTime() + " ms"); sb.append(" waited " + ti.getWaitedCount() + " for " + ti.getWaitedTime() + " ms"); if (ti.isSuspended()) { sb.append(" (suspended)"); } if (ti.isInNative()) { sb.append(" (running in native)"); } sb.append(CRLF); sb.append(INDENT3 + "java.lang.Thread.State: " + ti.getThreadState()); sb.append(CRLF); return sb.toString(); }
Formats the thread dump for one thread.
Params:
  • ti – the ThreadInfo describing the thread
Returns:the formatted thread dump
/** * Formats the thread dump for one thread. * * @param ti the ThreadInfo describing the thread * @return the formatted thread dump */
private static String getThreadDump(ThreadInfo ti) { StringBuilder sb = new StringBuilder(getThreadDumpHeader(ti)); for (LockInfo li : ti.getLockedSynchronizers()) { sb.append(INDENT2 + "locks " + li.toString() + CRLF); } boolean start = true; StackTraceElement[] stes = ti.getStackTrace(); Object[] monitorDepths = new Object[stes.length]; MonitorInfo[] mis = ti.getLockedMonitors(); for (int i = 0; i < mis.length; i++) { monitorDepths[mis[i].getLockedStackDepth()] = mis[i]; } for (int i = 0; i < stes.length; i++) { StackTraceElement ste = stes[i]; sb.append(INDENT2 + "at " + ste.toString() + CRLF); if (start) { if (ti.getLockName() != null) { sb.append(INDENT2 + "- waiting on (a " + ti.getLockName() + ")"); if (ti.getLockOwnerName() != null) { sb.append(" owned by " + ti.getLockOwnerName() + " Id=" + ti.getLockOwnerId()); } sb.append(CRLF); } start = false; } if (monitorDepths[i] != null) { MonitorInfo mi = (MonitorInfo)monitorDepths[i]; sb.append(INDENT2 + "- locked (a " + mi.toString() + ")"+ " index " + mi.getLockedStackDepth() + " frame " + mi.getLockedStackFrame().toString()); sb.append(CRLF); } } return sb.toString(); }
Formats the thread dump for a list of threads.
Params:
  • tinfos – the ThreadInfo array describing the thread list
Returns:the formatted thread dump
/** * Formats the thread dump for a list of threads. * * @param tinfos the ThreadInfo array describing the thread list * @return the formatted thread dump */
private static String getThreadDump(ThreadInfo[] tinfos) { StringBuilder sb = new StringBuilder(); for (ThreadInfo tinfo : tinfos) { sb.append(getThreadDump(tinfo)); sb.append(CRLF); } return sb.toString(); }
Check if any threads are deadlocked. If any, print the thread dump for those threads.
Returns:a deadlock message and the formatted thread dump of the deadlocked threads
/** * Check if any threads are deadlocked. If any, print * the thread dump for those threads. * * @return a deadlock message and the formatted thread dump * of the deadlocked threads */
public static String findDeadlock() { ThreadInfo[] tinfos = null; long[] ids = threadMXBean.findDeadlockedThreads(); if (ids != null) { tinfos = threadMXBean.getThreadInfo(threadMXBean.findDeadlockedThreads(), true, true); if (tinfos != null) { StringBuilder sb = new StringBuilder("Deadlock found between the following threads:"); sb.append(CRLF); sb.append(getThreadDump(tinfos)); return sb.toString(); } } return ""; }
Retrieves a formatted JVM thread dump. The default StringManager will be used.
Returns:the formatted JVM thread dump
/** * Retrieves a formatted JVM thread dump. * The default StringManager will be used. * * @return the formatted JVM thread dump */
public static String getThreadDump() { return getThreadDump(sm); }
Retrieves a formatted JVM thread dump. The given list of locales will be used to retrieve a StringManager.
Params:
  • requestedLocales – list of locales to use
Returns:the formatted JVM thread dump
/** * Retrieves a formatted JVM thread dump. * The given list of locales will be used * to retrieve a StringManager. * * @param requestedLocales list of locales to use * @return the formatted JVM thread dump */
public static String getThreadDump(Enumeration<Locale> requestedLocales) { return getThreadDump( StringManager.getManager(PACKAGE, requestedLocales)); }
Retrieve a JVM thread dump formatted using the given StringManager.
Params:
  • requestedSm – the StringManager to use
Returns:the formatted JVM thread dump
/** * Retrieve a JVM thread dump formatted * using the given StringManager. * * @param requestedSm the StringManager to use * @return the formatted JVM thread dump */
public static String getThreadDump(StringManager requestedSm) { StringBuilder sb = new StringBuilder(); synchronized(timeformat) { sb.append(timeformat.format(new Date())); } sb.append(CRLF); sb.append(requestedSm.getString("diagnostics.threadDumpTitle")); sb.append(" "); sb.append(runtimeMXBean.getVmName()); sb.append(" ("); sb.append(runtimeMXBean.getVmVersion()); String vminfo = System.getProperty(vminfoSystemProperty); if (vminfo != null) { sb.append(" " + vminfo); } sb.append("):" + CRLF); sb.append(CRLF); ThreadInfo[] tis = threadMXBean.dumpAllThreads(true, true); sb.append(getThreadDump(tis)); sb.append(findDeadlock()); return sb.toString(); }
Format contents of a MemoryUsage object.
Params:
  • name – a text prefix used in formatting
  • usage – the MemoryUsage object to format
Returns:the formatted contents
/** * Format contents of a MemoryUsage object. * @param name a text prefix used in formatting * @param usage the MemoryUsage object to format * @return the formatted contents */
private static String formatMemoryUsage(String name, MemoryUsage usage) { if (usage != null) { StringBuilder sb = new StringBuilder(); sb.append(INDENT1 + name + " init: " + usage.getInit() + CRLF); sb.append(INDENT1 + name + " used: " + usage.getUsed() + CRLF); sb.append(INDENT1 + name + " committed: " + usage.getCommitted() + CRLF); sb.append(INDENT1 + name + " max: " + usage.getMax() + CRLF); return sb.toString(); } return ""; }
Retrieves a formatted JVM information text. The default StringManager will be used.
Returns:the formatted JVM information text
/** * Retrieves a formatted JVM information text. * The default StringManager will be used. * * @return the formatted JVM information text */
public static String getVMInfo() { return getVMInfo(sm); }
Retrieves a formatted JVM information text. The given list of locales will be used to retrieve a StringManager.
Params:
  • requestedLocales – list of locales to use
Returns:the formatted JVM information text
/** * Retrieves a formatted JVM information text. * The given list of locales will be used * to retrieve a StringManager. * * @param requestedLocales list of locales to use * @return the formatted JVM information text */
public static String getVMInfo(Enumeration<Locale> requestedLocales) { return getVMInfo(StringManager.getManager(PACKAGE, requestedLocales)); }
Retrieve a JVM information text formatted using the given StringManager.
Params:
  • requestedSm – the StringManager to use
Returns:the formatted JVM information text
/** * Retrieve a JVM information text formatted * using the given StringManager. * * @param requestedSm the StringManager to use * @return the formatted JVM information text */
public static String getVMInfo(StringManager requestedSm) { StringBuilder sb = new StringBuilder(); synchronized(timeformat) { sb.append(timeformat.format(new Date())); } sb.append(CRLF); sb.append(requestedSm.getString("diagnostics.vmInfoRuntime")); sb.append(":" + CRLF); sb.append(INDENT1 + "vmName: " + runtimeMXBean.getVmName() + CRLF); sb.append(INDENT1 + "vmVersion: " + runtimeMXBean.getVmVersion() + CRLF); sb.append(INDENT1 + "vmVendor: " + runtimeMXBean.getVmVendor() + CRLF); sb.append(INDENT1 + "specName: " + runtimeMXBean.getSpecName() + CRLF); sb.append(INDENT1 + "specVersion: " + runtimeMXBean.getSpecVersion() + CRLF); sb.append(INDENT1 + "specVendor: " + runtimeMXBean.getSpecVendor() + CRLF); sb.append(INDENT1 + "managementSpecVersion: " + runtimeMXBean.getManagementSpecVersion() + CRLF); sb.append(INDENT1 + "name: " + runtimeMXBean.getName() + CRLF); sb.append(INDENT1 + "startTime: " + runtimeMXBean.getStartTime() + CRLF); sb.append(INDENT1 + "uptime: " + runtimeMXBean.getUptime() + CRLF); sb.append(INDENT1 + "isBootClassPathSupported: " + runtimeMXBean.isBootClassPathSupported() + CRLF); sb.append(CRLF); sb.append(requestedSm.getString("diagnostics.vmInfoOs")); sb.append(":" + CRLF); sb.append(INDENT1 + "name: " + operatingSystemMXBean.getName() + CRLF); sb.append(INDENT1 + "version: " + operatingSystemMXBean.getVersion() + CRLF); sb.append(INDENT1 + "architecture: " + operatingSystemMXBean.getArch() + CRLF); sb.append(INDENT1 + "availableProcessors: " + operatingSystemMXBean.getAvailableProcessors() + CRLF); sb.append(INDENT1 + "systemLoadAverage: " + operatingSystemMXBean.getSystemLoadAverage() + CRLF); sb.append(CRLF); sb.append(requestedSm.getString("diagnostics.vmInfoThreadMxBean")); sb.append(":" + CRLF); sb.append(INDENT1 + "isCurrentThreadCpuTimeSupported: " + threadMXBean.isCurrentThreadCpuTimeSupported() + CRLF); sb.append(INDENT1 + "isThreadCpuTimeSupported: " + threadMXBean.isThreadCpuTimeSupported() + CRLF); sb.append(INDENT1 + "isThreadCpuTimeEnabled: " + threadMXBean.isThreadCpuTimeEnabled() + CRLF); sb.append(INDENT1 + "isObjectMonitorUsageSupported: " + threadMXBean.isObjectMonitorUsageSupported() + CRLF); sb.append(INDENT1 + "isSynchronizerUsageSupported: " + threadMXBean.isSynchronizerUsageSupported() + CRLF); sb.append(INDENT1 + "isThreadContentionMonitoringSupported: " + threadMXBean.isThreadContentionMonitoringSupported() + CRLF); sb.append(INDENT1 + "isThreadContentionMonitoringEnabled: " + threadMXBean.isThreadContentionMonitoringEnabled() + CRLF); sb.append(CRLF); sb.append(requestedSm.getString("diagnostics.vmInfoThreadCounts")); sb.append(":" + CRLF); sb.append(INDENT1 + "daemon: " + threadMXBean.getDaemonThreadCount() + CRLF); sb.append(INDENT1 + "total: " + threadMXBean.getThreadCount() + CRLF); sb.append(INDENT1 + "peak: " + threadMXBean.getPeakThreadCount() + CRLF); sb.append(INDENT1 + "totalStarted: " + threadMXBean.getTotalStartedThreadCount() + CRLF); sb.append(CRLF); sb.append(requestedSm.getString("diagnostics.vmInfoStartup")); sb.append(":" + CRLF); for (String arg: runtimeMXBean.getInputArguments()) { sb.append(INDENT1 + arg + CRLF); } sb.append(CRLF); sb.append(requestedSm.getString("diagnostics.vmInfoPath")); sb.append(":" + CRLF); sb.append(INDENT1 + "bootClassPath: " + runtimeMXBean.getBootClassPath() + CRLF); sb.append(INDENT1 + "classPath: " + runtimeMXBean.getClassPath() + CRLF); sb.append(INDENT1 + "libraryPath: " + runtimeMXBean.getLibraryPath() + CRLF); sb.append(CRLF); sb.append(requestedSm.getString("diagnostics.vmInfoClassLoading")); sb.append(":" + CRLF); sb.append(INDENT1 + "loaded: " + classLoadingMXBean.getLoadedClassCount() + CRLF); sb.append(INDENT1 + "unloaded: " + classLoadingMXBean.getUnloadedClassCount() + CRLF); sb.append(INDENT1 + "totalLoaded: " + classLoadingMXBean.getTotalLoadedClassCount() + CRLF); sb.append(INDENT1 + "isVerbose: " + classLoadingMXBean.isVerbose() + CRLF); sb.append(CRLF); sb.append(requestedSm.getString("diagnostics.vmInfoClassCompilation")); sb.append(":" + CRLF); sb.append(INDENT1 + "name: " + compilationMXBean.getName() + CRLF); sb.append(INDENT1 + "totalCompilationTime: " + compilationMXBean.getTotalCompilationTime() + CRLF); sb.append(INDENT1 + "isCompilationTimeMonitoringSupported: " + compilationMXBean.isCompilationTimeMonitoringSupported() + CRLF); sb.append(CRLF); for (MemoryManagerMXBean mbean: memoryManagerMXBeans) { sb.append(requestedSm.getString("diagnostics.vmInfoMemoryManagers", mbean.getName())); sb.append(":" + CRLF); sb.append(INDENT1 + "isValid: " + mbean.isValid() + CRLF); sb.append(INDENT1 + "mbean.getMemoryPoolNames: " + CRLF); String[] names = mbean.getMemoryPoolNames(); Arrays.sort(names); for (String name: names) { sb.append(INDENT2 + name + CRLF); } sb.append(CRLF); } for (GarbageCollectorMXBean mbean: garbageCollectorMXBeans) { sb.append(requestedSm.getString("diagnostics.vmInfoGarbageCollectors", mbean.getName())); sb.append(":" + CRLF); sb.append(INDENT1 + "isValid: " + mbean.isValid() + CRLF); sb.append(INDENT1 + "mbean.getMemoryPoolNames: " + CRLF); String[] names = mbean.getMemoryPoolNames(); Arrays.sort(names); for (String name: names) { sb.append(INDENT2 + name + CRLF); } sb.append(INDENT1 + "getCollectionCount: " + mbean.getCollectionCount() + CRLF); sb.append(INDENT1 + "getCollectionTime: " + mbean.getCollectionTime() + CRLF); sb.append(CRLF); } sb.append(requestedSm.getString("diagnostics.vmInfoMemory")); sb.append(":" + CRLF); sb.append(INDENT1 + "isVerbose: " + memoryMXBean.isVerbose() + CRLF); sb.append(INDENT1 + "getObjectPendingFinalizationCount: " + memoryMXBean.getObjectPendingFinalizationCount() + CRLF); sb.append(formatMemoryUsage("heap", memoryMXBean.getHeapMemoryUsage())); sb.append(formatMemoryUsage("non-heap", memoryMXBean.getNonHeapMemoryUsage())); sb.append(CRLF); for (MemoryPoolMXBean mbean: memoryPoolMXBeans) { sb.append(requestedSm.getString("diagnostics.vmInfoMemoryPools", mbean.getName())); sb.append(":" + CRLF); sb.append(INDENT1 + "isValid: " + mbean.isValid() + CRLF); sb.append(INDENT1 + "getType: " + mbean.getType() + CRLF); sb.append(INDENT1 + "mbean.getMemoryManagerNames: " + CRLF); String[] names = mbean.getMemoryManagerNames(); Arrays.sort(names); for (String name: names) { sb.append(INDENT2 + name + CRLF); } sb.append(INDENT1 + "isUsageThresholdSupported: " + mbean.isUsageThresholdSupported() + CRLF); try { sb.append(INDENT1 + "isUsageThresholdExceeded: " + mbean.isUsageThresholdExceeded() + CRLF); } catch (UnsupportedOperationException ex) { // IGNORE } sb.append(INDENT1 + "isCollectionUsageThresholdSupported: " + mbean.isCollectionUsageThresholdSupported() + CRLF); try { sb.append(INDENT1 + "isCollectionUsageThresholdExceeded: " + mbean.isCollectionUsageThresholdExceeded() + CRLF); } catch (UnsupportedOperationException ex) { // IGNORE } try { sb.append(INDENT1 + "getUsageThreshold: " + mbean.getUsageThreshold() + CRLF); } catch (UnsupportedOperationException ex) { // IGNORE } try { sb.append(INDENT1 + "getUsageThresholdCount: " + mbean.getUsageThresholdCount() + CRLF); } catch (UnsupportedOperationException ex) { // IGNORE } try { sb.append(INDENT1 + "getCollectionUsageThreshold: " + mbean.getCollectionUsageThreshold() + CRLF); } catch (UnsupportedOperationException ex) { // IGNORE } try { sb.append(INDENT1 + "getCollectionUsageThresholdCount: " + mbean.getCollectionUsageThresholdCount() + CRLF); } catch (UnsupportedOperationException ex) { // IGNORE } sb.append(formatMemoryUsage("current", mbean.getUsage())); sb.append(formatMemoryUsage("collection", mbean.getCollectionUsage())); sb.append(formatMemoryUsage("peak", mbean.getPeakUsage())); sb.append(CRLF); } sb.append(requestedSm.getString("diagnostics.vmInfoSystem")); sb.append(":" + CRLF); Map<String,String> props = runtimeMXBean.getSystemProperties(); ArrayList<String> keys = new ArrayList<>(props.keySet()); Collections.sort(keys); for (String prop: keys) { sb.append(INDENT1 + prop + ": " + props.get(prop) + CRLF); } sb.append(CRLF); sb.append(requestedSm.getString("diagnostics.vmInfoLogger")); sb.append(":" + CRLF); List<String> loggers = loggingMXBean.getLoggerNames(); Collections.sort(loggers); for (String logger: loggers) { sb.append(INDENT1 + logger + ": level=" + loggingMXBean.getLoggerLevel(logger) + ", parent=" + loggingMXBean.getParentLoggerName(logger) + CRLF); } sb.append(CRLF); return sb.toString(); } }