Express (Distributed operating systems), v8.0 > Troubleshoot and support > Analyzing application server Java system dumps with the IBM Monitoring and Diagnostic Tools for Java - Dump Analyzer > Write Dump Analyzer modules for WAS diagnostics - Tutorial


Tutorial: Writing Dump Analyzer modules for WAS diagnostics


Putting it together: the complete source code for the WASThreadPoolsSample analyzer


WASThreadPoolsSampleX.java:

package com.ibm.dtfj.analyzer.was.samples;

import java.util.Iterator;

import com.ibm.dtfj.analyzer.ext.IAnalysisReport; import com.ibm.dtfj.analyzer.ext.IMessageLogger; import com.ibm.dtfj.analyzer.ext.IReport; import com.ibm.dtfj.analyzer.helpers.objectwrapper.ObjectWrapper; import com.ibm.dtfj.analyzer.helpers.objectwrapper.ObjectWrapperCollection; import com.ibm.dtfj.analyzer.j2se.wrappers.HashMapWrapper; import com.ibm.dtfj.analyzer.was.WASHeader; import com.ibm.dtfj.analyzer.was.WASVersion; import com.ibm.dtfj.analyzer.was.base.WASAnalyzerBase; import com.ibm.dtfj.java.JavaRuntime;

/** * Sample analyzer to print the WAS threads pools - version X */ public class WASThreadPoolsSampleX extends WASAnalyzerBase implements IReport {

/** * @see com.ibm.dtfj.analyzer.ext.IAnalyzerBase#getVersion() */ public String getVersion() { return "1.0.0.20080310-EXPERIMENTAL(alpha)"; }

/** * @see com.ibm.dtfj.analyzer.ext.IAnalyzerBase#getName() */ public String getName() { return "WASThreadPoolsSampleX"; }

/** * @see com.ibm.dtfj.analyzer.ext.IAnalyzerBase#getShortDescription() */ public String getShortDescription() { return getString("A sample analyzer that demonstrates how to write analysis modules (using WAS thread pools as an example)"); }

/** * @see com.ibm.dtfj.analyzer.ext.IAnalyzerBase#getLongDescription() */ public String getLongDescription() { return ( getShortDescription() + "\n" + getVersion() + "\n" + "This is the complete version of the sample analyzer from the tutorial "Writing Dump Analyzer modules for WAS diagnostics"" + "provided with the Dump Analyzer tool documentation"); }

/** * @see com.ibm.dtfj.analyzer.ext.IAnalyzerBase#isPrimaryAnalyzer() */ public boolean isPrimaryAnalyzer() { return true; }

/** * @see com.ibm.dtfj.analyzer.ext.IAnalyzerBase#getCategories() */ public String[] getCategories() { return new String[] { getClass().getPackage().getName() }; }

/* * Some state being built as part of the analysis */ private int numberOfPools = 0; private int numberOfAllocatedThreads = 0; private int numberOfPossibleThreads = 0; private int numberOfErrors = 0;

/* * A threshold to warn of possible thread overload (% of allocated vs. possible threads) * (not necessarily appropriate for actual problem detection; just to show the principle of such observations) */ private final static int THREAD_OVERLOAD_THRESHOLD = 80;

/** * @see com.ibm.dtfj.analyzer.ext.IReport#produceReport() */ public IAnalysisReport produceReport() { IAnalysisReport mainReport = allocateReport(null); IAnalysisReport summaryStatsReport = allocateSecondaryReport("summaryStats", null); IAnalysisReport summaryListReport = allocateSecondaryReport("summaryList", null); IAnalysisReport detailsReport = allocateSecondaryReport("details", null);

/* * Print a global header for this report */ WASHeader wasHeader = (WASHeader) getContext().loadAnalyzer(WASHeader.class.getName()); IAnalysisReport headerReport = wasHeader.produceReport(); mainReport.printReport("Common WebSphere header information", headerReport, IAnalysisReport.TAG_MAJORHEADING);

/* * Check that the WAS version is compatible with this analyzer (but continue anyway even if not) */ WASVersion wasVersion = (WASVersion) getContext().loadAnalyzer(WASVersion.class.getName()); wasVersion.checkCompatibleVersion(mainReport, "WASThreadPoolsBasic", new String[] { "6.1" }, false); //$NON-NLS-1$ //$NON-NLS-2$

/* * Scan all the pools to collect both summary and detailed information */ scanAllPools(summaryStatsReport, summaryListReport, detailsReport);

/* * Print the summary information */ mainReport.startSection("Summary information", IAnalysisReport.TAG_MAJORHEADING); mainReport.printReport("Global Statistics", summaryStatsReport); mainReport.printReport("Summary list of pools", summaryListReport); mainReport.endSection();

/* * Print the detailed information */ mainReport.printReport("Detailed information", detailsReport, IAnalysisReport.TAG_MAJORHEADING);

return mainReport; }

private void scanAllPools(IAnalysisReport summaryStatsReport, IAnalysisReport summaryListReport, IAnalysisReport detailsReport) { /* * Iterate over all the pools, computing the global statistics and bulding a list */ ObjectWrapperCollection pools = ObjectWrapperCollection.getObjectInstances(getContext(), "com/ibm/ws/util/ThreadPool"); for (int index = 0; index < pools.size(); index++) { ObjectWrapper pool = (ObjectWrapper) pools.get(index); scanOnePool(pool, summaryListReport, detailsReport); }

/* * Generate the global statistics report */ summaryStatsReport.printField("Number of pools successfully scanned", numberOfPools); summaryStatsReport.printField("Number of pools scanned with errors", numberOfErrors); summaryStatsReport.printField("Current number of pool threads", numberOfAllocatedThreads); summaryStatsReport.printField("Maximum possible number of pool threads", numberOfPossibleThreads); summaryStatsReport.printField("Number of JVM threads not in a pool", countJVMThreads() - numberOfAllocatedThreads); if (numberOfAllocatedThreads > ((THREAD_OVERLOAD_THRESHOLD / 100.0f) * numberOfPossibleThreads)) { logMessage(IMessageLogger.LEVEL_DBDA_OBSERVATION_LOW, "(minor observation) This process is currently using more than {0}% of all possible threads ({1}/{2})", new Object[] { new Integer(THREAD_OVERLOAD_THRESHOLD), new Integer(numberOfAllocatedThreads), new Integer(numberOfPossibleThreads) }, summaryStatsReport); } }

private void scanOnePool(ObjectWrapper pool, IAnalysisReport summaryListReport, IAnalysisReport detailsReport) { int curSize; int maxSize;

try { /* * Generate one line of output for this pool in the summary report */ summaryListReport.startFormatSection(IAnalysisReport.FORMAT_COLUMNS, "2 1 1"); { pool.printValueAtPath(summaryListReport, "", "name"); pool.printValueAtPath(summaryListReport, "Size", "poolSize_"); pool.printValueAtPath(summaryListReport,"", ""); } summaryListReport.endSection();

/* * Generate a detailed record for this pool in the details report */ IAnalysisReport out2 = pool.startPrintGroup(detailsReport, "Thread Pool", pool.getParent(), ObjectWrapper.MODE_NONE, IAnalysisReport.TAG_STANDOUT); { pool.printValueAtPath(out2, "Pool name", "name"); out2.startFormatSection(IAnalysisReport.FORMAT_COLUMNS, "1 1"); { pool.printValueAtPath(out2, "Min size", "minimumPoolSize_"); maxSize = pool.printValueAtPath(out2, "Max size", "maximumPoolSize_").getIntegerValue(); } out2.endSection(); curSize = pool.printValueAtPath(out2, "Current size", "poolSize_").getIntegerValue(); pool.printCollectionValueReportsAtPath(out2, "List of Threads", "Thread", "threads_", HashMapWrapper.class.getName(), ThreadPoolWorkerWrapper.class.getName()); } pool.endPrintGroup();

/* * Update global statistics */ numberOfAllocatedThreads += curSize; numberOfPossibleThreads += maxSize; numberOfPools++; } catch (Exception e) { logExceptionMessage("Error extracting information for pool", e, summaryListReport); numberOfErrors++; } }

/** * Use low-level DTFJ primitives to count the total number of threads in this JVM * (independent of whether they are in a WAS thread pool or not) * @return the number of JVM threads, according to DTFJ */ private int countJVMThreads() { JavaRuntime runtime = getContext().getCurrentJavaRuntime(); Iterator it = runtime.getThreads(); int count = 0; while (it.hasNext()) { it.next(); count++; } return count; } }


ThreadPoolWorkerWrapper.java:

package com.ibm.dtfj.analyzer.was.samples;

import com.ibm.dtfj.analyzer.ext.IAnalysisReport; import com.ibm.dtfj.analyzer.ext.IReport; import com.ibm.dtfj.analyzer.ext.IWrapper; import com.ibm.dtfj.analyzer.helpers.objectwrapper.ObjectWrapper; import com.ibm.dtfj.analyzer.util.IdentityStringHelper;

/** * Sample wrapper for a com/ibm/ws/util/ThreadPool$Worker */ public class ThreadPoolWorkerWrapper extends ObjectWrapper implements IReport, IWrapper { /** * @see com.ibm.dtfj.analyzer.ext.IWrapper#setParent(Object) */ public void setParent(Object parent) { super.setParent(parent); if (! this.isInstanceOf("com/ibm/ws/util/ThreadPool$Worker")) { throw new IllegalArgumentException("Attempting to initialize a ThreadPoolWorkerWrapper with an object of the wrong type " + IdentityStringHelper.buildIdentString(parent)); } } /** * @see com.ibm.dtfj.analyzer.ext.IReport#produceReport() */ public IAnalysisReport produceReport() { IAnalysisReport out = allocateReport(null); this.printValueAtPath(out, "Thread name", "name"); this.printValueAtPath(out, "Thread number", "threadNumber"); this.printValueAtPath(out, "Priority", "priority"); this.printValueAtPath(out, "Start time", "startTime"); return out; } }


Next Topic


Putting it together: sample output for the WASThreadPoolsSample analyzer