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


Generate Reports with a Summary and a Details Section

So far, our analyzer generates a large monolithic report: it scans the dump for all the information that we want to extract, and prints it in the report essentially in the order that it is found. This is obviously the simplest approach from the perspective of the people implementing the analyzer. But from the perspective of people who will have to read the report generated by this analyzer, we may want to provide a more user-friendly structure, for example by showing a summary of the most important information near the top of the report, followed by more details further down in the report. We can do this by taking advantage of the ability to nest multiple reports into another higher-level report.

For this sample, let's show a summary section with some global statistics about all thread pools and a short list of of threads pools (one line per pool), followed by a detailed section that shows all the information about each pool.

Here is a synopsis of the new code:

public class WASThreadPoolsSampleX extends WASAnalyzerBase implements IReport {

public IAnalysisReport produceReport() { IAnalysisReport mainReport = allocateReport(null); IAnalysisReport summaryStatsReport = allocateSecondaryReport("summaryStats", null); IAnalysisReport summaryListReport = allocateSecondaryReport("summaryList", null); IAnalysisReport detailsReport = allocateSecondaryReport("details", null);

/* * 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) { ... }

}

Basically, instead of writing all the output directly into a single report, we now allocate and use 4 distinct reports:

The main produceReport() method allocates these 4 report objects, invokes scanAllPools() to do all the work to extract information about all the pools and fill-in the information in the 3 secondary reports, and then constructs the main report by using IAnalysisReport.printReport() to include each secondary report in the main report.

Let's look at the implementation of scanAllPools():

...
   /*
    * 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;

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); // ... other statistics ... }

private void scanOnePool(ObjectWrapper pool, IAnalysisReport summaryListReport, IAnalysisReport detailsReport) { // ... see code from previous sections ... }

We first declare a few object instance fields numberOfPools, numberOfAllocatedThreads(), etc. to gather statistics. scanAllPools() and ScanOnePool() will increment these statistics as they iterate through all the pools.

scanAllPools() first iterates over each pool, and calls scanOnePool() once for each pool. scanOnePool() contains code similar to that from previous sections in this tutorials. It appends information to both the summaryListReport() and the detailsReport, in parallel.

Finally, scanAllPools() fills the the summaryStartReport() with the global statistics that have been collected during the entire scan.


Next Topic


Integrate the Analyzer into the Tool Menu