Author: rjung
Date: Mon Apr 29 10:58:01 2013
New Revision: 1476959

URL: http://svn.apache.org/r1476959
Log:
First draft of Diagnostics class.

Added:
    tomcat/trunk/java/org/apache/tomcat/util/Diagnostics.java   (with props)

Added: tomcat/trunk/java/org/apache/tomcat/util/Diagnostics.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/Diagnostics.java?rev=1476959&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/Diagnostics.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/Diagnostics.java Mon Apr 29 
10:58:01 2013
@@ -0,0 +1,429 @@
+/*
+ * 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: StringManager
+// XXX TODO: Sort logger names and system property keys in getVMInfo()
+// XXX TODO: Add memory and GC MBeans to getVMInfo()
+// XXX Optional: Wire setters to the manager:
+//               log level setter, verbose class loading setter,
+//               and threadMXBean setters.
+
+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.MonitorInfo;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.LogManager;
+import java.util.logging.LoggingMXBean;
+
+public class Diagnostics {
+
+    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 org.apache.juli.logging.Log log=
+        org.apache.juli.logging.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 LoggingMXBean loggingMXBean =
+        LogManager.getLoggingMXBean();
+    private static final MemoryMXBean memoryMXBeans =
+        ManagementFactory.getMemoryMXBean();
+    private static final List<GarbageCollectorMXBean> garbageCollectorMXBean =
+        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.
+     *
+     * @return true if thread contention monitoring is enabled
+     */
+    public static boolean isThreadContentionMonitoringEnabled() {
+        return threadMXBean.isThreadContentionMonitoringEnabled();
+    }
+
+    /**
+     * 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.
+     *
+     * @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.
+     *
+     * @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
+     */
+    public static void resetPeakThreadCount() {
+        threadMXBean.resetPeakThreadCount();
+    }
+
+    /**
+     * 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
+     *
+     * @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");
+        }
+    }
+
+    /**
+     * 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.
+     *
+     * @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.
+     *
+     * @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.
+     *
+     * @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 "";
+    }
+
+    /**
+     * Retrieve a formatted JVM thread dump.
+     * @return the thread dump
+     */
+    public static String getThreadDump() {
+        StringBuilder sb = new StringBuilder();
+
+        synchronized(timeformat) {
+            sb.append(timeformat.format(new Date()));
+        }
+        sb.append(CRLF);
+
+        sb.append("Full thread dump ");
+        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();
+    }
+
+    /**
+     * Retrieve a formatted JVM thread dump.
+     * @return the thread dump
+     */
+    public static String getVMInfo() {
+        StringBuilder sb = new StringBuilder();
+
+        synchronized(timeformat) {
+            sb.append(timeformat.format(new Date()));
+        }
+        sb.append(CRLF);
+
+        sb.append("Runtime information:" + 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("OS information:" + 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("ThreadMXBean capabilities:" + 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("Thread counts:" + 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("Class loading:" + 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("Class compilation:" + 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);
+
+        sb.append("Path information:" + 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("Startup arguments:" + CRLF);
+        for (String arg: runtimeMXBean.getInputArguments()) {
+            sb.append(INDENT1 + arg + CRLF);
+        }
+        sb.append(CRLF);
+
+        sb.append("System properties:" + CRLF);
+        Map<String,String> props = runtimeMXBean.getSystemProperties();
+        for (String prop: props.keySet()) {
+            sb.append(INDENT1 + prop + ": " + props.get(prop) + CRLF);
+        }
+        sb.append(CRLF);
+
+        sb.append("Logger information:" + CRLF);
+        for (String logger: loggingMXBean.getLoggerNames()) {
+            sb.append(INDENT1 + logger +
+                      ": level=" + loggingMXBean.getLoggerLevel(logger) +
+                      ", parent=" + loggingMXBean.getParentLoggerName(logger) 
+ CRLF);
+        }
+        sb.append(CRLF);
+
+        return sb.toString();
+    }
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/util/Diagnostics.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/trunk/java/org/apache/tomcat/util/Diagnostics.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to