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 Custom Wrapper Analyzer

So far (see previous topic) we have managed to print a list of the threads that are contained in a thread pool:

List of Threads: java/util/HashMap@0x036F18B8 (4 entries)       
    Thread: com/ibm/ws/util/ThreadPool$Worker@0x012F3158 com/ibm/ws/util/ThreadPool$Worker@0x012F3158
    Thread: com/ibm/ws/util/ThreadPool$Worker@0x011ACE18 com/ibm/ws/util/ThreadPool$Worker@0x011ACE18
    Thread: com/ibm/ws/util/ThreadPool$Worker@0x012CE728 com/ibm/ws/util/ThreadPool$Worker@0x012CE728
    Thread: com/ibm/ws/util/ThreadPool$Worker@0x011819F0 com/ibm/ws/util/ThreadPool$Worker@0x011819F0

But that is still not sufficient. We don't want to see a simple reference to the com/ibm/ws/util/ThreadPool$Worker object associated with each thread. We want to see some information about that thread. The way to do this is to write a new analyzer module: a Custom Wrapper specifically designed to extract and print information about an instance of com/ibm/ws/util/ThreadPool$Worker.

Custom Wrappers are similar to the generic ObjectWrapper and standard J2SE wrappers (HashMapWrapper, etc.) that are part of the library of standard analyzers shipped with the Dump Analyzer tool. But Custom Wrappers correspond to types of objects that were not anticipated when the standard library was put together. We must write a new one ourselves.

Here is the code for the Custom Wrapper for com/ibm/ws/util/ThreadPool$Worker:

public class ThreadPoolWorkerWrapper extends ObjectWrapper implements IReport, IWrapper {

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)); } }

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; } }

and the code in the main analyzer that invokes this Custom Wrapper when listing the threads:

pool.printCollectionValueReportsAtPath(out2, "List of Threads", "Thread", "threads_", HashMapWrapper.class.getName(), ThreadPoolWorkerWrapper.class.getName());

The output looks as follows:

List of Threads: java/util/HashMap@0x036F18B8 (4 entries)       
     Thread: com/ibm/ws/util/ThreadPool$Worker@0x012F3158 com/ibm/ws/util/ThreadPool$Worker@0x012F3158
            Thread name: "TCPChannel.DCS : 3"
            Thread number: "00000016"
            Priority: 5
            Start time: 0
     Thread: com/ibm/ws/util/ThreadPool$Worker@0x011ACE18 com/ibm/ws/util/ThreadPool$Worker@0x011ACE18
            Thread name: "TCPChannel.DCS : 1"
            Thread number: "00000012"
            Priority: 5
            Start time: 0
     Thread: com/ibm/ws/util/ThreadPool$Worker@0x012CE728 com/ibm/ws/util/ThreadPool$Worker@0x012CE728
            Thread name: "TCPChannel.DCS : 2"
            Thread number: "00000015"
            Priority: 5
            Start time: 0
     Thread: com/ibm/ws/util/ThreadPool$Worker@0x011819F0 com/ibm/ws/util/ThreadPool$Worker@0x011819F0
            Thread name: "TCPChannel.DCS : 0"
            Thread number: "00000011"
            Priority: 5
            Start time: 0

The key points are as follows:


Declare the Custom Wrapper class

The structure of ThreadPoolWorkerWrapper is similar to that of other analyzers, such as the main WASThreadPoolsSample analyzer that we've been developing in this tutorial. Except that instead of extending WASAnalyzerBase (a generic common base class for WAS analyzers), it extends ObjectWrapper. ThreadPoolWorkerWrapper is effectively a specialized version of ObjectWrapper, that offers all the generic functionality of ObjectWrapper that is suitable for any type of object, plus some specific functionality tailored to interpreting and reporting on com/ibm/ws/util/ThreadPool$Worker objects.


Special responsibilities for a wrapper-type analyzer: IWrapper and setParent()

Unlike WASThreadPoolsSample which is a global analyzer that operates in the scope of the entire dump, ThreadPoolWorkerWrapper represents one particular instance of one particular object extracted from that dump. So it needs to be initialized to specify which particular object instance it represents. This is the purpose of the IWrapper interface, which declares the method setParent().

When the tool framework allocates a new instance of ThreadPoolWorkerWrapper and detects that this analyzer implements the IWrapper interface, the framework invokes the analyzer's setParent() method, passing it a reference to the parent object, i.e. the low-level DTFJ object representation that corresponds to the object in the original dump being analyzed.

Our ThreadPoolWorkerWrapper implementation does not need to do much in its setParent() method, because we rely on our superclass ObjectWrapper to do all the hard work of keeping track of the parent object and mediating access to it. So we forward the invocation to ObjectWrapper's own setParent() method.

In passing, though, it is wise to check that we are being initialized with a parent of the correct type (com/ibm/ws/util/ThreadPool$Worker). We do this with the help of the isInstanceOf() method, which is itself implemented by our ObjectWrapper superclass. Note that ObjectWrapper itself implements isInstanceOf(), but has no reason to use it to check anything, because it is generic and can deal with any type of parent object. It is only the specialized ThreadPoolWorkerWrapper that needs to worry about being initialized with the correct type of parent object.

Notes:


Producing a custom report

ThreadPoolWorkerWrapper overrides the produceReport() method from its ObjectWrapper superclass. We want to produce a customized report for com/ibm/ws/util/ThreadPool$Worker objects, and not the generic report from ObjectWrapper which prints all the fields from the object indiscriminately.

The implementation of produceReport() can use all the facilities of the ObjectWrapper superclass to access and print specific fields. In this example, we choose to simply print four key fields from a com/ibm/ws/util/ThreadPool$Worker, without any fancy formatting or grouping.


Invoke the Custom Wrapper

Back in the WASThreadPoolsSample analyzer, instead of using the printCollectionEntriesAtPath() method to print all the entries in the HashMap that contains the list of threads, we now use the printCollectionValueReportsAtPath() method. This method differs from the former in that it takes an additional parameter (the name of the wrapper analyzer to use to print individual entries -- in this case ThreadPoolWorkerWrapper) and that instead of printing a simple object reference for each entry in the HashMap, it instantiates a ThreadPoolWorkerWrapper for each entry and invokes its produceReport() method.


Controlling the printing of the key and value for each entry

As noted earlier in a previous topic, the output from this code still prints the object reference to each com/ibm/ws/util/ThreadPool$Worker twice for each entry in the list. This breaks down as follows:

  1. We first print an object reference for the key in each entry in the HashMap, which is the com/ibm/ws/util/ThreadPool$Worker object
  2. Next we print the title of the custom report for the value of each entry in the HashMap, which is also the com/ibm/ws/util/ThreadPool$Worker object
  3. Next we print the body of the custom report associated with the com/ibm/ws/util/ThreadPool$Worker object, as implemented by the ThreadPoolWorkerWrapper

To avoid this double printing of the object reference, we have two alternatives:

We won't go into further detail of these alternatives here. Please refer to the API documentation for further information.


Next Topic


Extract Values from Data Structures, Exception Handling