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


A Simple Analyzer to Examine Data Structures

Let's start writing a simple analyzer that scans through the data structures that represent all the thread pools in a WAS process, and prints key information about each pool:

public class WASThreadPoolsSample1 extends WASAnalyzerBase implements IReport {

public IAnalysisReport produceReport() { IAnalysisReport out = allocateReport(null); ObjectWrapperCollection pools = ObjectWrapperCollection.getObjectInstances(getContext(), "com/ibm/ws/util/ThreadPool"); for (int index = 0; index < pools.size(); index++) { ObjectWrapper pool = (ObjectWrapper) pools.get(index); pool.printValueAtPath(out, "Pool name", "name"); pool.printValueAtPath(out, "Min size", "minimumPoolSize_"); pool.printValueAtPath(out, "Max size", "maximumPoolSize_"); pool.printValueAtPath(out, "Current size", "poolSize_"); pool.printValueAtPath(out, "List of Threads", "threads_"); out.printLiteral(""); } return out; } }

Here is a fragment of the output from this analyzer, run on a small WAS process dump:

...

Pool name: "WLMMonitorSleeper" Min size: 0 Max size: 10 Current size: 1 List of Threads: java/util/HashMap@0x01167330

Pool name: "SoapConnectorThreadPool" Min size: 3 Max size: 5 Current size: 2 List of Threads: java/util/HashMap@0x01F910C0

Pool name: "WebContainer" Min size: 10 Max size: 50 Current size: 0 List of Threads: java/util/HashMap@0x02149D50

...

Let's examine the key aspects of this analyzer:


Analyzer structure

The analyzer is a simple Java class, defined as in the previous example of the Hello World Analyzer. It's main purpose is to generate a report, so it contains a produceReport() method that will be invoked by the tool framework when that analyzer is requested, and that returns a report containing the desired information.

Unlike the Hello World Analyzer, this analyzer needs to do some work inside its produceReport() method to actually find the information that it wants to produce.


Enumerating all instances of the ThreadPool data structure

We happen to know that, in WAS, each thread pool is represented by a data structure of class com.ibm.ws.util.ThreadPool. So we need some code to look for all instances of that class present inside the dump:

ObjectWrapperCollection pools = ObjectWrapperCollection.getObjectInstances(getContext(), "com/ibm/ws/util/ThreadPool");

ObjectWrapperCollection is a special analyzer, part of the library of standard analyzers shipped with the Dump Analyzer tool, whose purpose is to find collections of objects: all the instances of a given class, or all the subclasses of a given class, etc. Here, we use the static factory method ObjectWrapperCollection.getObjectInstances(), which returns an instance of the ObjectWrapperCollection analyzer that represents the desired list of instances. The parameters are as follows:

ObjectWrapperCollection is an analyzer, that happens to implement the java.util.Collection from the standard Java Collections framework. So we can use that interface to enumerate and extract the items from the collection, i.e. each of the instances of com/ibm/ws/util/ThreadPool that are found in the dump.

Each item in the collection is represented by another standard analyzer from the library, of type ObjectWrapper. Each instance of the ObjectWrapper analyzer represents one particular object instance from the dump being analyzed.

So we iterate over these instances simply as follows: (we could also have used a Java Iterator over the collection)

for (int index = 0; index
< pools.size(); index++) {
    ObjectWrapper pool = (ObjectWrapper) pools.get(index);
    // ... do whatever we need to with each "pool" object }


Print fields from one object instance

So now, we have a local variable pool that references an ObjectWrapper analyzer that represents one particular instance of a com/ibm/ws/util/ThreadPool object from the dump being analyzed. We want to print the contents of that object, i.e. print the value of its various fields:

pool.printValueAtPath(out, "Pool name", "name");
pool.printValueAtPath(out, "Min size", "minimumPoolSize_");
pool.printValueAtPath(out, "Max size", "maximumPoolSize_");
pool.printValueAtPath(out, "Current size", "poolSize_");
pool.printValueAtPath(out, "List of Threads", "threads_");

This code is pretty self-explanatory. The ObjectWrapper analyzer exports a method printValueAtPath(), that looks for a particular field in the target object being represented by this ObjectWrapper and prints the value of that field. The arguments are as follows:

In this case, we are printing five fields named "name", "minimumPoolSize_", "maximumPoolSize_", "poolSize_" and "threads_"). We picked those fields by looking at the definition of com/ibm/ws/util/ThreadPool, either from the source code or by examining it with another analyzer or command in the Dump Analyzer tool itself, and we decided that these five fields were the ones that we were particularly interested in for this new analyzer.

If the value of a given field is a String or one of the primitive Java types (int, boolean, etc.) or Integer, Boolean, etc., that value is printed normally.

If the value of a given field is an object reference, the printValueAtPath() method prints a standard representation for all object references, like java/util/HashMap@0x01167330 in the example above. This means that this particular field contains a reference to a HashMap object that happens to be at the address 0x01167330 in the dump being analyzed. In the following sections of this tutorial, we will see how we can follow that reference to see the fields inside that referenced object itself, and other that it in turn references, etc.

If the name of the field specified in printValueAtPath() does not correspond to a valid field defined in the target object, then this method prints an error indication like [ <analyzererror>] in lieu of the expected value of the field.

Notes:


Separating the output for each of the thread pools

The code in this analyzer iterates over all the thread pool objects, and prints some fields for each object. We need a way to mark in the report when the information for one thread pool object is ended and we start the information for the next object.

In this simplest example, we use the construct

out.printLiteral("");
to insert a blank line in the report. In the next section of this tutorial, we will learn some more powerful ways to control the format the report.


Next Topic


Write and Formatting Reports